PREAMBLE

   NORMALLY, MODE IS INTEGER

''DEFINE TO MEANS FOR UNIQUENESS - ROUTINES

   DEFINE ABS.ROUNDUP.F TO MEAN ARF
   DEFINE CALCULATE.INTERMEDIATE.VARIABLES TO MEAN CIV
   DEFINE CALCULATE.INVESTMENT.TAX.CREDIT.RATE TO MEAN CITCR
   DEFINE CALCULATE.IPEG.COEFFICIENTS TO MEAN CIC
   DEFINE CALCULATE.PVDEP TO MEAN CPVDEP
   DEFINE CALCULATE.PVECC TO MEAN CPVECC
   DEFINE CALCULATE.PVEWC TO MEAN CPVEWC
   DEFINE CHANGE.A.REAL TO MEAN CAR
   DEFINE CHANGE.WORKING.VARIABLES TO MEAN CWV
   DEFINE CHECK.FOR.A.MATCH TO MEAN CFAM
   DEFINE CHECK.THE.NEXT.INPUT.WORD.FOR.ABORT TO MEAN CTNIWFA
   DEFINE CHECK.THE.NEXT.NONBLANK.LINE.FOR.DEFAULT TO MEAN CTNNLFD
   DEFINE COMPARE.STRINGS TO MEAN CS
   DEFINE COPY.AN.ARRAY TO MEAN CAA
   DEFINE DETERMINE.CHARACTER.COUNT TO MEAN DCC
   DEFINE DETERMINE.THE.FILE.LOCATION.OF.A.CASE TO MEAN DTFLOAC
   DEFINE DISPLAY.THE.CHANGED.VARIABLES TO MEAN DTCV
   DEFINE DISPLAY.THE.COMPANY.DATA TO MEAN DTCD
   DEFINE DISPLAY.THE.INDEPENDENT.VARIABLES TO MEAN DTIV
   DEFINE DISPLAY.THE.INTEGER.LIMITS TO MEAN DTIL
   DEFINE DISPLAY.THE.PROCESS.DATA TO MEAN DTPD
   DEFINE DISPLAY.THE.REAL.LIMITS TO MEAN DTRL
   DEFINE DISPLAY.THE.TRANSFORMATION.MATRIX TO MEAN DTTM
   DEFINE GET.FILE.DIRECTORY TO MEAN GFD
   DEFINE GET.MACHINE.SPECIFICATIONS TO MEAN GMS
   DEFINE GET.PARSER.VOCABULARY TO MEAN GPV
   DEFINE GET.THE.CHARACTER.ATTRIBUTES.AND.HASH.THE.WORD TO MEAN GTCAAHT
   DEFINE GET.THE.IPEG.INPUTS.FOR.THIS.CASE TO MEAN GTIIFTC
   DEFINE INITIALIZE.THE.IPEG.PROGRAM TO MEAN ITIP
   DEFINE INITIALIZE.VARIABLE.NAMES.MIN.MAX.AND.DEFAULT.VALUES TO MEAN IVNMMAD
   DEFINE INTERPRET.THE.NEXT.WORD.IF.NOT.ABORT TO MEAN ITNWINA
   DEFINE INTERPRET.THE.USERS.NEXT.WORD TO MEAN ITUNW
   DEFINE LABEL.A.TICK.MARK TO MEAN LATM
   DEFINE LIST.AN.INDEPENDENT.VARIABLE TO MEAN LAIV
   DEFINE LOAD.SOME.TEXT TO MEAN LST
   DEFINE LOAD.THE.COMPANY.DATA TO MEAN LTCD
   DEFINE LOAD.THE.PROCESS.DATA TO MEAN LTPD
   DEFINE MAKE.THE.UNITS.SINGULAR TO MEAN MTUS
   DEFINE MOVE.TEXT TO MEAN MT
   DEFINE OBTAIN.THE.INDEPENDENT.VARIABLE.AND.VALUES TO MEAN OTIVAV
   DEFINE PLOT.A.CURVE.ON.THE.PRINTER TO MEAN PACOTP
   DEFINE PLOT.THE.RESULTS TO MEAN PLTR
   DEFINE POSITION.AN.ENTITY.FILE.TO.THE.FIRST.LINE.OF.THE.FIRST.ENTITY
      TO MEAN PAEFTTF
   DEFINE PROCESS.THE.CONTINUATION.WORDS TO MEAN PTCW
   DEFINE PRINT.CHARACTERS TO MEAN PC
   DEFINE PRINT.COLUMN.HEADINGS TO MEAN PCH
   DEFINE PRINT.SENSITIVITY.REPORT.HEADING TO MEAN PSRH
   DEFINE PRINT.TEXT TO MEAN PT
   DEFINE PRINT.THE.PRICE TO MEAN PTP
   DEFINE PRINT.THE.RESULTS TO MEAN PRTR
   DEFINE PUT.THE.NEXT.INPUT.WORD TO MEAN PTNIW
   DEFINE QUOTE.TEXT TO MEAN QT
   DEFINE READ.A.LINE.OF.TEXT TO MEAN RALOT
   DEFINE READ.A.REAL TO MEAN RARL
   DEFINE READ.A.REAL.VECTOR TO MEAN RARV
   DEFINE READ.A.REFERENT TO MEAN RAR
   DEFINE READ.A.TEXT.VECTOR.FROM.FILE TO MEAN RATVFF
   DEFINE READ.AN.INTEGER TO MEAN RAI
   DEFINE READ.CONTEXT.MESSAGES TO MEAN RCM
   DEFINE RELEASE.A.TEXT.VECTOR TO MEAN RATV
   DEFINE REORDER.THE.VECTOR TO MEAN RTV
   DEFINE SCALE.SOME.DATA TO MEAN SSD
   DEFINE WRITE.A.REAL.VALUE TO MEAN WARV
   DEFINE WRITE.A.REAL.VECTOR TO MEAN WARVE
   DEFINE WRITE.A.TEXT.VECTOR TO MEAN WATV

''DEFINE TO MEANS FOR INDEPENDENT VARIABLES

   DEFINE EQPT.P TO MEAN WORKING(1)
   DEFINE SQFT.P TO MEAN WORKING(2)
   DEFINE DLAB.P TO MEAN WORKING(3)
   DEFINE MATS.P TO MEAN WORKING(4)
   DEFINE UTIL.P TO MEAN WORKING(5)

   DEFINE EL.P   TO MEAN WORKING(6)
   DEFINE EITCR.P  TO MEAN WORKING(7)
   DEFINE FL.P     TO MEAN WORKING(8)
   DEFINE BETA.P   TO MEAN WORKING(9)
   DEFINE X.P      TO MEAN WORKING(10)
   DEFINE NU.P     TO MEAN WORKING(11)
   DEFINE Z.P      TO MEAN WORKING(12)
   DEFINE RLAB.P   TO MEAN WORKING(13)
   DEFINE RUTIL.P  TO MEAN WORKING(14)
   DEFINE G.P      TO MEAN WORKING(15)
   DEFINE W.P      TO MEAN WORKING(16)
   DEFINE TAU.P    TO MEAN WORKING(17)
   DEFINE LAMBDA.P TO MEAN WORKING(18)
   DEFINE IR.P     TO MEAN WORKING(19)
   DEFINE R.P      TO MEAN WORKING(20)
   DEFINE P1.P     TO MEAN WORKING(21)
   DEFINE P2.P     TO MEAN WORKING(22)
   DEFINE P3.P     TO MEAN WORKING(23)
   DEFINE D1.P     TO MEAN WORKING(24)
   DEFINE D2.P     TO MEAN WORKING(25)
   DEFINE GF.P     TO MEAN WORKING(26)
   DEFINE GE.P     TO MEAN WORKING(27)
   DEFINE TS.P     TO MEAN WORKING(28)
   DEFINE TM.P     TO MEAN WORKING(29)
   DEFINE TC.P     TO MEAN WORKING(30)
   DEFINE L.P      TO MEAN WORKING(31)
   DEFINE A.P      TO MEAN WORKING(32)
   DEFINE UF.P     TO MEAN WORKING(33)
   DEFINE LF.P     TO MEAN WORKING(34)
   DEFINE T.P      TO MEAN WORKING(35)
   DEFINE M.P      TO MEAN WORKING(36)
   DEFINE B.P      TO MEAN WORKING(37)
   DEFINE TLF.P    TO MEAN WORKING(38)
   DEFINE XEC.P    TO MEAN WORKING(39)
   DEFINE XFC.P    TO MEAN WORKING(40)
   DEFINE XOPR.P   TO MEAN WORKING(41)
   DEFINE N.P      TO MEAN WORKING(42)
   DEFINE CRT.P    TO MEAN WORKING(43)

''OTHER DEFINE TO MEANS

   DEFINE TERMINATED TO MEAN 1=2
   DEFINE ITERATING TO MEAN RESUME SUBSTITUTION  ''A NULL COMMAND
   DEFINE SELECT TO MEAN GO TO
   DEFINE CASE TO MEAN 'CASE
   DEFINE ENDSELECT TO MEAN HERE
   DEFINE SAY TO MEAN WRITE AS B 1,

   SUBSTITUTE THESE 3 LINES FOR STASH
   LET XXX.UNIT = WRITE.V
   USE THE BUFFER FOR OUTPUT
   WRITE AS /,

   SUBSTITUTE THIS LINE FOR INTO
   NOW LOAD.SOME.TEXT  YIELDING

   SUBSTITUTE THESE 3 LINES FOR CHECK.FOR.ABORT
   IF ABORT.FLAG = 1  ''(ON)
      GO TO ABORT
   OTHERWISE
THE SYSTEM HAS
   A CONTEXT.MESSAGES IN WORD 2,                  ''POINTER TO TEXT
   A USER.TEXT IN WORD 3,                         ''POINTER TO TEXT
   A T.MATRIX IN WORD 4,                          ''POINTER TO REAL MATRIX
   A TABLE IN WORD 5,                             ''POINTER TO REAL MATRIX
   AN E.VECTOR IN WORD 6,                         ''POINTER TO REAL VECTOR
   A V.VECTOR IN WORD 7,                          ''POINTER TO REAL VECTOR
   A C IN WORD 8,                                 ''POINTER TO REAL VECTOR
   AN OPR IN WORD 9,                              ''POINTER TO REAL VECTOR
   AN OTX IN WORD 10,                             ''POINTER TO REAL VECTOR
   A BVAL IN WORD 11,                             ''POINTER TO REAL VECTOR
   AN INS IN WORD 12,                             ''POINTER TO REAL VECTOR
   AN INT IN WORD 13,                             ''POINTER TO REAL VECTOR
   AN RPL IN WORD 14,                             ''POINTER TO REAL VECTOR
   AN ITC IN WORD 15,                             ''POINTER TO REAL VECTOR
   AN EQR IN WORD 16,                             ''POINTER TO REAL VECTOR
   A WCAP IN WORD 17,                             ''POINTER TO REAL VECTOR
   A FAC IN WORD 18,                              ''POINTER TO REAL VECTOR
   A PVELP IN WORD 19,                            ''POINTER TO REAL VECTOR
   A PVECC IN WORD 20,                            ''POINTER TO REAL VECTOR
   A PVITC IN WORD 21,                            ''POINTER TO REAL VECTOR
   A PVEWC IN WORD 22,                            ''POINTER TO REAL VECTOR
   A PVDEP IN WORD 23,                            ''POINTER TO REAL VECTOR
   A PVSUCI IN WORD 24,                           ''POINTER TO REAL VECTOR
   A NORMAL.INPUT.UNIT IN WORD 25,
   A NORMAL.OUTPUT.UNIT IN WORD 26,
   AN IPEG.FILE IN WORD 27,
   A VOCABULARY.FILE IN WORD 28,
   A MACHINE.SPECIFICATIONS.FILE IN WORD 29,
   A SAVED IN WORD 30,                            ''POINTER TO REAL VECTOR
   A WORKING IN WORD 31,                          ''POINTER TO REAL VECTOR
   A CHARACTERS.PER.WORD IN WORD 32,
   AN IP.FILE.POS IN WORD 33,
   A SIZE IN WORD 34,
   A COMPANY.REFERENT IN WORD 35,                 ''POINTER TO TEXT
   A PROCESS.REFERENT IN WORD 36,                 ''POINTER TO TEXT
   A PROCESS.FLAG IN WORD 37,
   A REPORT.YEAR IN WORD 38,
   AN OLD.SIZE IN WORD 39,
   AN OLD.COMPANY.REFERENT IN WORD 40,            ''POINTER TO TEXT
   A COMPANY.DESCRIPTIVE.NAME IN WORD 41,         ''POINTER TO TEXT
   A PROCESS.LIST IN WORD 42,                     ''PTR TO ARRAY OF TEXT PTR'S
   AN I.QUAN IN WORD 43,
   AN INDUSTRY.PRODUCTION.UNITS IN WORD 44,       ''POINTER TO TEXT
   A P.QUAN IN WORD 45,
   A PROCESS.PRODUCT.UNITS IN WORD 46,            ''POINTER TO TEXT
   A PROCESS.DESCRIPTIVE.NAME IN WORD 47,         ''POINTER TO TEXT
   AN OLD.REPORT.YEAR IN WORD 48,
   A SCRATCH.FILE IN WORD 49,
   A TRACE IN WORD 50,                            ''POINTER TO INTEGER VECTOR
   AN ABORT.FLAG IN WORD 51,
   AN ABORT.PTR IN WORD 52,                       ''POINTER TO TEXT
   AN XXX.UNIT IN WORD 53,
   AN N.VARIABLES IN WORD 54,
   AN RITCE IN WORD 55,
   A K IN WORD 56,
   A CAPK IN WORD 57,
   A GCRF IN WORD 58,
   A B1 IN WORD 59,
   A VD IN WORD 60,
   A VS IN WORD 61,
   A TSU IN WORD 62,
   A TEC IN WORD 63,
   A PHI IN WORD 64,
   A YE IN WORD 65,
   A Q IN WORD 66,
   A TCC IN WORD 67,
   A DFE IN WORD 68,
   A PVSUCD IN WORD 69,
   AN F1 IN WORD 70,
   AN IVNAMES IN WORD 71,                         ''PTR TO ARRAY OF TEXT PTR'S
   A VMIN IN WORD 72,                             ''POINTER TO REAL VECTOR
   A VMAX IN WORD 73,                             ''POINTER TO REAL VECTOR
   A VDEF IN WORD 74,                             ''POINTER TO REAL VECTOR
   AN N.VALUES IN WORD 75,
   AN ALTERNATE.PRINT.FILE IN WORD 76,
   A VNAMES IN WORD 77,                          ''PTR TO ARRAY OF TEXT PTR'S
   A TIME.OF.DAY IN WORD 78,                     ''POINTER TO TEXT
   A CURRENT.DATE IN WORD 79,                    ''POINTER TO TEXT
   AN OUTPUT.LIST IN WORD 80,                    ''POINTER TO INTEGER VECTOR
   A REPORT.TITLE IN WORD 81,                    ''POINTER TO TEXT
   AN IVINDEX IN WORD 82,
   AN IVUNITS IN WORD 83,                        ''PTR TO ARRAY OF TEXT PTR'S
   A RELEASE.NUMBER IN WORD 84,
   A TB IN WORD 85,
   A Y IN WORD 86,
   AN I.QUANS IN WORD 87,
   A P.QUANS IN WORD 88

''GLOBAL ARRAYS
   DEFINE CONTEXT.MESSAGES, TRACE, IVNAMES, VNAMES, OUTPUT.LIST, IVUNITS
      AS 1-DIM, INTEGER ARRAYS

   DEFINE USER.TEXT, TIME.OF.DAY, CURRENT.DATE AS 1-DIM, ALPHA ARRAYS

   DEFINE T.MATRIX, TABLE AS 2-DIM, REAL ARRAYS

   DEFINE E.VECTOR, V.VECTOR, C, OPR, OTX, BVAL, INS, INT, RPL, ITC, EQR,
      WCAP, FAC, PVELP, PVECC, PVITC, PVEWC, PVDEP, PVSUCI, SAVED, WORKING,
      VMIN, VMAX, VDEF
      AS 1-DIM, REAL ARRAYS

''GLOBAL VARIABLES
   DEFINE NORMAL.INPUT.UNIT, NORMAL.OUTPUT.UNIT, IPEG.FILE,
      VOCABULARY.FILE, MACHINE.SPECIFICATIONS.FILE, CHARACTERS.PER.WORD,
      IP.FILE.POS, SIZE, COMPANY.REFERENT, PROCESS.REFERENT, PROCESS.FLAG,
      REPORT.YEAR, OLD.SIZE, OLD.COMPANY.REFERENT, COMPANY.DESCRIPTIVE.NAME,
      PROCESS.LIST, INDUSTRY.PRODUCTION.UNITS, PROCESS.PRODUCT.UNITS,
      PROCESS.DESCRIPTIVE.NAME, OLD.REPORT.YEAR, SCRATCH.FILE, ABORT.FLAG,
      ABORT.PTR, XXX.UNIT, N.VARIABLES, N.VALUES, ALTERNATE.PRINT.FILE,
      REPORT.TITLE, IVINDEX
      AS INTEGER VARIABLES

   DEFINE I.QUAN, P.QUAN, RITCE, K, CAPK, GCRF, B1, VD, VS, TSU, TEC, PHI,
      YE, Q, TCC, DFE, PVSUCD, F1, TB, Y, I.QUANS, P.QUANS
      AS REAL VARIABLES

   DEFINE RELEASE.NUMBER AS AN ALPHA VARIABLE

''FUNCTION DEFINITIONS
   DEFINE ABS.ROUNDUP.F AS AN INTEGER FUNCTION

''RELEASEABLE ROUTINES
   DEFINE INITIALIZE.THE.IPEG.PROGRAM, GET.PARSER.VOCABULARY,
      GET.FILE.DIRECTORY, GET.MACHINE.SPECIFICATIONS,
      GET.THE.CHARACTER.ATTRIBUTES.AND.HASH.THE.WORD,
      PROCESS.THE.CONTINUATION.WORDS,
      INITIALIZE.VARIABLE.NAMES.MIN.MAX.AND.DEFAULT.VALUES,
      READ.CONTEXT.MESSAGES
      AS RELEASABLE ROUTINES

THE SYSTEM OWNS AN IPEG.DIRECTORY

TEMPORARY ENTITIES

   EVERY DIRECTORY.ENTRY MAY BELONG TO THE IPEG.DIRECTORY AND HAS
      A P.IPEG.DIRECTORY IN WORD 1,
      AN S.IPEG.DIRECTORY IN WORD 2,
      AN M.IPEG.DIRECTORY IN WORD 3,
      A REFERENCE IN WORD 4,                      ''POINTER TO TEXT
      A SIZE.INDEX IN WORD 5,
      AND A LINES.OF.DATA IN WORD 6

   DEFINE IPEG.DIRECTORY AS A FIFO SET

   DEFINE REFERENCE, SIZE.INDEX, LINES.OF.DATA AS INTEGER VARIABLES

THE SYSTEM OWNS A VECTOR

TEMPORARY ENTITIES

   EVERY ELEMENT BELONGS TO THE VECTOR AND HAS
      A WORD.POINTER IN WORD 1,
      AN R1VALUE IN WORD 2,
      AND AN R2VALUE IN WORD 3

   DEFINE VECTOR AS A SET RANKED BY LOW R1VALUE

   DEFINE WORD.POINTER AS AN INTEGER VARIABLE

   DEFINE R1VALUE, R2VALUE AS REAL VARIABLES

   THE SYSTEM OWNS SOME POINTS AND SOME TICK.MARKS

   TEMPORARY ENTITIES

   EVERY POINT
      BELONGS TO THE POINTS,
      AND HAS A P.POINTS IN WORD 1,
      AN S.POINTS IN WORD 2,
      AN M.POINTS IN WORD 3,
      A LINE.NUMBER IN WORD 4,
      A CHARACTER.NUMBER IN WORD 5,
      A PLOT.SYMBOL IN WORD 6

   EVERY TICK.MARK
      BELONGS TO THE TICK.MARKS,
      AND HAS A P.TICK.MARKS IN WORD 1,
      AN S.TICK.MARKS IN WORD 2,
      AN M.TICK.MARKS IN WORD 3,
      A LINE.NUMBER IN WORD 4,
      A CHARACTER.NUMBER IN WORD 5,
      A PLOT.SYMBOL IN WORD 6,
      A TYPE IN WORD 7,
      A VALUE.FLAG IN WORD 8,
      A VALUE IN WORD 9

   DEFINE POINTS AS A SET RANKED BY LOW LINE.NUMBER

   DEFINE TICK.MARKS AS A SET RANKED BY LOW LINE.NUMBER

   DEFINE LINE.NUMBER, CHARACTER.NUMBER, TYPE, VALUE.FLAG
      AS INTEGER VARIABLES
   DEFINE PLOT.SYMBOL AS AN ALPHA VARIABLE
   DEFINE VALUE AS A REAL VARIABLE

PERMANENT ENTITIES

   EVERY HASHING.PAGE HAS
      THE F.VOCAB                   IN WORD 1
      AND OWNS A VOCABULARY

TEMPORARY ENTITIES

   EVERY VOCABULARY.WORD HAS
      THE TEXT.POINTER              IN WORD 1,
      THE NUMBER.OF.CHARACTERS      IN WORD 2,
      THE CONTINUATION.WORD         IN WORD 3,
      THE S.VOCAB                   IN WORD 4,
      THE F.DEFINITIONS             IN WORD 5,
      AND BELONGS TO A VOCABULARY
      AND OWNS SOME DEFINITIONS
      DEFINE VOCABULARY AS A LIFO SET WITHOUT L, N, P, M ATTRIBUTES

   EVERY MEANING HAS
      THE CONTEXT                   IN WORD 1,
      THE CASE.NO                   IN WORD 2,
      THE S.DEFINITIONS             IN WORD 3,
      AND BELONGS TO THE DEFINITIONS
      DEFINE DEFINITIONS AS A LIFO SET WITHOUT L, N, P, M ATTRIBUTES

   ''GLOBAL VARIABLE FOR THE PARSER PRINT.EXCEPTION.MESSAGE
   DEFINE START.OF.WORD AS AN INTEGER VARIABLE

END
MAIN

   DEFINE CHOICE, I, J, K, FIRST.TIME AS INTEGER VARIABLES
   DEFINE PRICE, DEFLATOR AS REAL VARIABLES

   NOW INITIALIZE.THE.IPEG.PROGRAM

''***** S 1
   IF TRACE(1) = 1  ''(ON)
      SKIP 1 LINE
      ITERATING FOR EACH DIRECTORY.ENTRY IN IPEG.DIRECTORY, DO
         WRITE AS B 10, "REFERENCE IS"
         NOW QUOTE.TEXT  GIVEN REFERENCE(DIRECTORY.ENTRY)
         WRITE SIZE.INDEX(DIRECTORY.ENTRY) AS S 2, "SIZE = ", I 3
         WRITE LINES.OF.DATA(DIRECTORY.ENTRY) AS S 2, "LINES = ", I 4, /
      REPEAT  ''FOR NEXT DIRECTORY.ENTRY
   ALWAYS
''***** E 1

   SKIP 1 LINE
   IF IPEG.DIRECTORY IS EMPTY
      PRINT 1 LINE THUS
YOUR INPUT FILE IS EMPTY SO THIS RUN IS BEING ABORTED.
      STOP  ''THE PROGRAM
   OTHERWISE

   LET OLD.SIZE = 0
   LET OLD.COMPANY.REFERENT = 0
   LET OLD.REPORT.YEAR = 0

   ITERATING UNTIL TERMINATED, DO
      PRINT 1 LINE THUS
DO YOU WISH TO PROCESS ANOTHER CASE?
      NOW INTERPRET.THE.USERS.NEXT.WORD  GIVEN 1, 0
         YIELDING CHOICE

      IF CHOICE = 2  ''NO
         STOP  ''THE PROGRAM
      OTHERWISE

      NOW GET.THE.IPEG.INPUTS.FOR.THIS.CASE
      IF ABORT.FLAG = 1  ''(ON)
         PRINT 1 LINE WITH "*****" THUS
***** WARNING: THIS CASE HAS BEEN ABORTED.
         SKIP 1 LINE
         LET ABORT.FLAG = 0
         CYCLE  ''TO ANOTHER CASE
      OTHERWISE

      ''INITIALIZE WORKING VALUES OF THE INDEPENDENT VARIABLES
      FOR I = 1 TO N.VARIABLES,
         LET WORKING(I) = SAVED(I)
      LET P.QUAN = P.QUANS
      LET I.QUAN = I.QUANS

      IF CARD IS NEW
         PRINT 1 LINE THUS
DO YOU WISH TO DISPLAY ANY OF THE SAVED VARIABLES?
         START NEW CARD
      ALWAYS
      NOW INTERPRET.THE.USERS.NEXT.WORD  GIVEN 1, 0
         YIELDING CHOICE
      IF CHOICE = 1  ''YES
         NOW DISPLAY.THE.INDEPENDENT.VARIABLES  GIVEN SAVED(*)
      ALWAYS

      LET RITCE = EITCR.P
      NOW CALCULATE.IPEG.COEFFICIENTS
      LET PRICE = C(1) * EQPT.P + C(2) * SQFT.P + C(3) * DLAB.P
                + C(4) * MATS.P + C(5) * UTIL.P

      IF CARD IS NEW
         PRINT 1 LINE THUS
DO YOU WISH TO DISPLAY THE TRANSFORMATION MATRIX?
         START NEW CARD
      ALWAYS
      NOW INTERPRET.THE.USERS.NEXT.WORD  GIVEN 1, 0
         YIELDING CHOICE
      IF CHOICE = 1  ''YES
         NOW DISPLAY.THE.TRANSFORMATION.MATRIX
      ALWAYS

      NOW PRINT.THE.PRICE  GIVEN PRICE

      ''PERFORM THE USER SPECIFIED SENSITIVITY RUNS
      ITERATING UNTIL TERMINATED, DO
         SKIP 1 LINE
         PRINT 1 LINE THUS
DO YOU WISH TO PERFORM ANOTHER SENSITIVITY STUDY?
         NOW INTERPRET.THE.USERS.NEXT.WORD  GIVEN 1, 0
            YIELDING CHOICE
         IF CHOICE = 2  ''NO
            LEAVE  ''THE LOOP AND TRY ANOTHER CASE
         OTHERWISE

         IF CARD IS NEW
            PRINT 1 LINE THUS
DO YOU WISH TO REINITIALIZE THE WORKING VARIABLES?
            START NEW CARD
         ALWAYS
         NOW INTERPRET.THE.NEXT.WORD.IF.NOT.ABORT  GIVEN 1
            YIELDING CHOICE
         CHECK.FOR.ABORT
         IF CHOICE = 1  ''YES
            FOR I = 1 TO N.VARIABLES,
               LET WORKING(I) = SAVED(I)
            LET P.QUAN = P.QUANS
            LET I.QUAN = I.QUANS
         ALWAYS

         IF CARD IS NEW
            PRINT 1 LINE THUS
DO YOU WISH TO CHANGE ANY OF THE WORKING VARIABLE VALUES?
            START NEW CARD
         ALWAYS
         NOW INTERPRET.THE.NEXT.WORD.IF.NOT.ABORT  GIVEN 1
            YIELDING CHOICE
         CHECK.FOR.ABORT
         IF CHOICE = 1  ''YES
            NOW CHANGE.WORKING.VARIABLES
         ALWAYS

         NOW DISPLAY.THE.CHANGED.VARIABLES

         NOW OBTAIN.THE.INDEPENDENT.VARIABLE.AND.VALUES
         CHECK.FOR.ABORT

         IF IVINDEX = 0  ''USER WISHES TO COMPUTE AND PRINT PRICE
            LET RITCE = EITCR.P
            NOW CALCULATE.IPEG.COEFFICIENTS
            LET PRICE = C(1) * EQPT.P + C(2) * SQFT.P + C(3) * DLAB.P
                      + C(4) * MATS.P + C(5) * UTIL.P
            IF CARD IS NEW
               PRINT 1 LINE THUS
DO YOU WISH TO DISPLAY THE TRANSFORMATION MATRIX?
               START NEW CARD
            ALWAYS
            NOW INTERPRET.THE.USERS.NEXT.WORD  GIVEN 1, 0
               YIELDING CHOICE
            IF CHOICE = 1  ''YES
               NOW DISPLAY.THE.TRANSFORMATION.MATRIX
            ALWAYS
            NOW PRINT.THE.PRICE  GIVEN PRICE
            CYCLE  ''TO NEXT SENSITIVITY STUDY
         OTHERWISE

         LET FIRST.TIME = 0
         ITERATING FOR I = 1 TO N.VALUES, DO
            LET WORKING(IVINDEX) = TABLE(1,I)
            IF IVINDEX = 6 OR (IVINDEX > 31 AND IVINDEX ) 39)
               NOW CALCULATE.INVESTMENT.TAX.CREDIT.RATE
                  YIELDING RITCE
            ELSE
               LET RITCE = EITCR.P
            ALWAYS

            IF FIRST.TIME = 0 OR IVINDEX > 5
               NOW CALCULATE.IPEG.COEFFICIENTS
               LET FIRST.TIME = 1
            ALWAYS

            ''COMPUTE THE COST VECTOR
            FOR J = 1 TO 5,
               LET E.VECTOR(J) = WORKING(J)
            ITERATING FOR K = 1 TO 17, DO
               LET V.VECTOR(K) = 0.0
               FOR J = 1 TO 5,
                  ADD T.MATRIX(K,J) * E.VECTOR(J) TO V.VECTOR(K)
            REPEAT  ''FOR NEXT K

            ''STORE RESULTS IN TABLE
            LET DEFLATOR = (1.0 + G.P)  ** (REPORT.YEAR - SAVED(29))
            FOR J = 1 TO 5,
               LET TABLE(J+1,I) = T.MATRIX(1,J)
            LET TABLE(3,I) = TABLE(3,I) * DEFLATOR
            LET PRICE = V.VECTOR(1) * DEFLATOR
            LET TABLE(7,I) = PRICE / P.QUAN
            LET TABLE(8,I) = PRICE / I.QUAN
            FOR J = 1 TO 16,
               LET TABLE(J+8,I) = V.VECTOR(J+1) * DEFLATOR

         REPEAT  ''FOR THE NEXT I

         NOW PRINT.THE.RESULTS

         NOW PLOT.THE.RESULTS

         RELEASE TABLE

         CYCLE  ''TO NEXT SENSITIVITY STUDY

         'ABORT'  ''HERE IF USER ENTERS ABORT
         SAY "***** YOUR SENSITIVITY STUDY HAS BEEN ABORTED.", /
         LET ABORT.FLAG = 0

      REPEAT  ''UNTIL USER FINISHES SENSITIVITY STUDIES

      LET OLD.SIZE = SIZE
      LET OLD.REPORT.YEAR = REPORT.YEAR
      RELEASE OLD.COMPANY.REFERENT
      STORE COMPANY.REFERENT IN OLD.COMPANY.REFERENT
   REPEAT  ''UNTIL TERMINATED

   STOP
END
ROUTINE TO INITIALIZE.THE.IPEG.PROGRAM

   DEFINE TOD, HOUR, MINUTE AS INTEGER VARIABLES

   DEFINE CPW TO MEAN CHARACTERS.PER.WORD

   NOW GET.MACHINE.SPECIFICATIONS

   STASH "ABORT" INTO ABORT.PTR

   LET LINES.V = INF.C

   ''INITIALIZE CURRENT.DATE AND TIME.OF.DAY
   ''THE DATE AND TIME OF DAY MUST BE ON THE FIRST LINE OF SCRATCH.FILE
   ''IN 8 CHARACTER ALPHA FIELDS
   REWIND SCRATCH.FILE
   USE SCRATCH.FILE FOR INPUT
   NOW READ.A.REFERENT  YIELDING CURRENT.DATE(*)
   NOW READ.A.REFERENT  YIELDING TOD
   ''CHANGE TOD TO A MORE PLEASANT FORMAT
   LET XXX.UNIT = WRITE.V
   USE THE BUFFER FOR OUTPUT
   WRITE AS /
   NOW PRINT.TEXT  GIVEN TOD
   USE THE BUFFER FOR INPUT
   READ HOUR, MINUTE AS B 1, I 2, S 1, I 2
   USE THE BUFFER FOR OUTPUT
   WRITE AS /
   IF HOUR > 12
      LET HOUR = HOUR - 12
      WRITE AS B 7, "PM"
   ELSE
      WRITE AS B 7, "AM"
   ALWAYS
   IF HOUR = 12
      WRITE AS B 7, "PM"
      IF MINUTE = 0
         WRITE AS B 7, "N "
      ALWAYS
   ALWAYS
   IF HOUR = 0 AND MINUTE = 0
      WRITE AS B 7, "M "
   ALWAYS
   WRITE HOUR, MINUTE AS B 1, I 2, ":", I 2
   IF OUT.F(4) = " "
      LET OUT.F(4) = "0"
   ALWAYS
   NOW LOAD.SOME.TEXT  YIELDING TIME.OF.DAY(*)
   RELEASE TOD
   USE NORMAL.INPUT.UNIT FOR INPUT

   ''ESTABLISH THE GLOBAL ARRAYS WHICH ARE "STATIC" IN SIZE
   RESERVE T.MATRIX(*,*) AS 17 BY 5
   STORE T.MATRIX(1,*) IN C(*)
   STORE T.MATRIX(2,*) IN OPR(*)
   STORE T.MATRIX(3,*) IN OTX(*)
   STORE T.MATRIX(4,*) IN BVAL(*)
   STORE T.MATRIX(5,*) IN INS(*)
   STORE T.MATRIX(6,*) IN INT(*)
   STORE T.MATRIX(7,*) IN RPL(*)
   STORE T.MATRIX(8,*) IN ITC(*)
   STORE T.MATRIX(9,*) IN EQR(*)
   STORE T.MATRIX(10,*) IN WCAP(*)
   STORE T.MATRIX(11,*) IN FAC(*)
   STORE T.MATRIX(12,*) IN PVELP(*)
   STORE T.MATRIX(13,*) IN PVECC(*)
   STORE T.MATRIX(14,*) IN PVITC(*)
   STORE T.MATRIX(15,*) IN PVEWC(*)
   STORE T.MATRIX(16,*) IN PVDEP(*)
   STORE T.MATRIX(17,*) IN PVSUCI(*)
   RESERVE E.VECTOR(*) AS 5
   RESERVE V.VECTOR(*) AS 17
   LET N.VARIABLES = 43
   RESERVE WORKING(*) AS N.VARIABLES
   RESERVE SAVED(*) AS N.VARIABLES

   NOW GET.PARSER.VOCABULARY
   NOW GET.FILE.DIRECTORY
   NOW INITIALIZE.VARIABLE.NAMES.MIN.MAX.AND.DEFAULT.VALUES

   WRITE RELEASE.NUMBER AS B 1,"WELCOME TO THE IPEG PROGRAM, RELEASE ",A CPW, /

   RELEASE INITIALIZE.THE.IPEG.PROGRAM

   RETURN
END
ROUTINE TO GET.MACHINE.SPECIFICATIONS

   DEFINE I AS AN INTEGER VARIABLE

   DEFINE CPW TO MEAN CHARACTERS.PER.WORD

   LET MACHINE.SPECIFICATIONS.FILE = 1
   REWIND MACHINE.SPECIFICATIONS.FILE
   USE MACHINE.SPECIFICATIONS.FILE FOR INPUT
   LET EOF.V = 1

   READ CHARACTERS.PER.WORD
   START NEW CARD
   READ VOCABULARY.FILE
   START NEW CARD
   READ IPEG.FILE
   START NEW CARD
   READ SCRATCH.FILE
   START NEW CARD
   READ NORMAL.INPUT.UNIT
   START NEW CARD
   READ NORMAL.OUTPUT.UNIT
   START NEW CARD
   READ ALTERNATE.PRINT.FILE
   START NEW CARD
   READ RELEASE.NUMBER AS A CPW
   SKIP 1 FIELD

   ''GET TRACE FLAGS
   RESERVE TRACE(*) AS 50
   ITERATING UNTIL DATA IS ENDED,
      READ I, TRACE(I)

   USE NORMAL.INPUT.UNIT FOR INPUT
   USE NORMAL.OUTPUT.UNIT FOR OUTPUT
   LET LINES.V = INF.C   ''TURN OFF AUTOMATIC PAGINATION

   RELEASE GET.MACHINE.SPECIFICATIONS

   RETURN
END
ROUTINE TO GET.PARSER.VOCABULARY

   DEFINE VOCABULARY.WORD, PRIOR.WORD, AND NEXT.WORD.IN.PHRASE
      AS INTEGER VARIABLES

   ''BEFORE GETTING PARSER VOCABULARY, GET THE MESSAGES FOR EACH CONTEXT.
   REWIND VOCABULARY.FILE
   USE VOCABULARY.FILE FOR INPUT
   NOW READ.CONTEXT.MESSAGES

   ''NOW GET THE PARSER VOCABULARY
   CREATE EACH HASHING.PAGE(97)

   ''GET ALL THE KEYWORDS (AND PHRASES) IN THE PROGRAM VOCABULARY AND THEIR
   ''MEANINGS IN EACH CONTEXT SPECIFIED.
   LET EOF.V = 1
   ITERATING UNTIL DATA IS ENDED, DO

      ''SETUP THE VOCABULARY WORDS CHARACTER ATTRIBUTES AND HASHING
      NOW GET.THE.CHARACTER.ATTRIBUTES.AND.HASH.THE.WORD
         YIELDING VOCABULARY.WORD

      ''IF THERE IS A PHRASE, LINK UP THE CONTINUATION WORDS
      LET PRIOR.WORD = VOCABULARY.WORD
      ITERATING UNTIL MODE IS NOT ALPHA, DO
         NOW PROCESS.THE.CONTINUATION.WORDS GIVEN PRIOR.WORD
            YIELDING NEXT.WORD.IN.PHRASE
         LET PRIOR.WORD = NEXT.WORD.IN.PHRASE
      LOOP ''UNTIL THE PHRASE IS COMPLETE

      ''GET THE WORD (OR PHRASE) DEFINITIONS
      ITERATING UNTIL MODE IS ALPHA, DO
         CREATE A MEANING
         READ CONTEXT(MEANING) AND CASE.NO(MEANING)
         FILE THE MEANING IN THE DEFINITIONS(VOCABULARY.WORD)
      REPEAT ''UNTIL ALL MEANINGS ARE READ IN
      START NEW CARD
   LOOP ''UNTIL ALL VOCABULARY WORDS ARE PROCESSED

   USE NORMAL.INPUT.UNIT FOR INPUT
   USE NORMAL.OUTPUT.UNIT FOR OUTPUT
   RELEASE GET.THE.CHARACTER.ATTRIBUTES.AND.HASH.THE.WORD
   RELEASE PROCESS.THE.CONTINUATION.WORDS
   RELEASE GET.PARSER.VOCABULARY

   RETURN
END
ROUTINE TO READ.CONTEXT.MESSAGES

   DEFINE I, LAST.CONTEXT AS INTEGER VARIABLES
   DEFINE MAX.CONTEXT AS A REAL VARIABLE

   ''READ EACH MESSAGE
   ITERATING UNTIL TERMINATED, DO  ''FOR EACH MESSAGE

      IF CARD IS NEW
         START NEW CARD
      ALWAYS
      IF MODE IS ALPHA  ''END OF MESSAGES
         LEAVE  ''THE LOOP
      OTHERWISE  ''READ THE NEXT MESSAGE NUMBER AND MESSAGE

      CREATE AN ELEMENT
      FILE THIS ELEMENT IN THE VECTOR  ''BEFORE ANYTHING TO INSURE NO RANKING
      ''USE R2VALUE(ELEMENT) TO TEMPORARILY STORE MSG NO. - R2VAL NOT RANKED
      READ R2VALUE(ELEMENT)
      IF CARD IS NOT NEW  ''THERE IS A MESSAGE FOR THIS CONTEXT
         NOW READ.A.LINE.OF.TEXT  YIELDING WORD.POINTER(ELEMENT)
      ALWAYS  ''IF CARD WERE NEW (ABOVE), IMPLYING NO MSG FOR THIS CONTEXT,
              ''WORD.POINTER(ELEMENT) WOULD BE ZERO

   LOOP  ''FOR EACH CONTEXT MESSAGE

   START NEW CARD  ''TO SKIP ALPHA USED TO TERMINATE ABOVE LOOP

   ''NOW LOAD THE VECTOR INTO THE GLOBAL ARRAY "CONTEXT.MESSAGES"
   FOR EACH ELEMENT IN THE VECTOR,
      COMPUTE MAX.CONTEXT AS THE MAX OF R2VALUE(ELEMENT)
   LET LAST.CONTEXT = MAX.CONTEXT  ''REAL TO INTEGER
   RESERVE CONTEXT.MESSAGES  AS LAST.CONTEXT
   ITERATING FOR EACH ELEMENT IN THE VECTOR, DO
      LET I = R2VALUE(ELEMENT)
      STORE WORD.POINTER(ELEMENT) IN CONTEXT.MESSAGES(I)
      REMOVE THIS ELEMENT FROM THE VECTOR
      DESTROY THIS ELEMENT
   LOOP  ''FOR EACH ELEMENT

   RELEASE READ.CONTEXT.MESSAGES

   RETURN

END
ROUTINE TO GET.THE.CHARACTER.ATTRIBUTES.AND.HASH.THE.WORD
   YIELDING VOCABULARY.WORD

   DEFINE VOCABULARY.WORD, CHARACTERS.IN.HASHED.WORD, AND HASHING.INDEX
      AS INTEGER VARIABLES
   DEFINE WORD.TEXT AS A 1-DIMENSIONAL, ALPHA ARRAY

   ''READ THE CHARACTERS INTO A LOCALLY DEFINED ALPHA ARRAY
   NOW PUT.THE.NEXT.INPUT.WORD ''INTO A LOCALLY-DEFINED ALPHA ARRAY
      YIELDING WORD.TEXT(*) AND CHARACTERS.IN.HASHED.WORD

   ''CREATE THE VOCABULARY WORD AND GET ITS CHARACTER ATTRIBUTES
   CREATE A VOCABULARY.WORD
   STORE WORD.TEXT(*) IN TEXT.POINTER(VOCABULARY.WORD)
   LET NUMBER.OF.CHARACTERS(VOCABULARY.WORD) = CHARACTERS.IN.HASHED.WORD

   ''DETERMINE THE PROPER HASHING PAGE AND LINK THE VOCABULARY WORD WITH IT
   STORE WORD.TEXT(1) IN HASHING.INDEX       '' ALPHA TO INTEGER
   LET HASHING.INDEX = ABS.F(HASHING.INDEX)  ''DROP THE SIGN
   LET HASHING.INDEX = MOD.F(HASHING.INDEX,N.HASHING.PAGE) + 1
   FILE THIS VOCABULARY.WORD IN THE VOCABULARY(HASHING.INDEX)
   RETURN
END
ROUTINE TO PROCESS.THE.CONTINUATION.WORDS GIVEN PRIOR.WORD
   YIELDING NEXT.WORD.IN.PHRASE

   DEFINE PRIOR.WORD, NEXT.WORD.IN.PHRASE, LENGTH.OF.CONTINUATION.WORD
      AS INTEGER VARIABLES
   DEFINE WORD.TEXT AS A 1-DIMENSIONAL, ALPHA ARRAY

   ''READ THE CHARACTERS INTO A LOCALLY DEFINED ALPHA ARRAY
   NOW PUT.THE.NEXT.INPUT.WORD ''INTO A LOCALLY-DEFINED ALPHA ARRAY
      YIELDING WORD.TEXT(*) AND LENGTH.OF.CONTINUATION.WORD

   ''CREATE THE VOCABULARY WORD AND GET ITS CHARACTER ATTRIBUTES
   CREATE A VOCABULARY.WORD CALLED NEXT.WORD.IN.PHRASE
   STORE WORD.TEXT(*) IN TEXT.POINTER(NEXT.WORD.IN.PHRASE)
   LET NUMBER.OF.CHARACTERS(NEXT.WORD.IN.PHRASE)=LENGTH.OF.CONTINUATION.WORD

   ''LINK THE CONTINUATION WORD WITH THE PRIOR WORD
   LET CONTINUATION.WORD(PRIOR.WORD) = NEXT.WORD.IN.PHRASE
   RETURN
END

ROUTINE TO GET.FILE.DIRECTORY

   DEFINE ID.MARK AS AN INTEGER VARIABLE

   REWIND IPEG.FILE
   USE IPEG.FILE FOR INPUT
   LET EOF.V = 1

   IF DATA IS NOT ENDED
      READ ID.MARK AS B 1, A 1
      ITERATING UNTIL ID.MARK = "+", DO
         CREATE A DIRECTORY.ENTRY
         READ SIZE.INDEX(DIRECTORY.ENTRY)
         NOW READ.A.REFERENT  YIELDING REFERENCE(DIRECTORY.ENTRY)
         READ LINES.OF.DATA(DIRECTORY.ENTRY)
         FILE THIS DIRECTORY.ENTRY IN THE IPEG.DIRECTORY
         START NEW CARD
         READ ID.MARK AS B 1, A 1
      REPEAT  ''UNTIL END OF DIRECTORY IS ENCOUNTERED

      START NEW CARD
      LET IP.FILE.POS = N.IPEG.DIRECTORY + 2
   ALWAYS

   USE NORMAL.INPUT.UNIT FOR INPUT
   RELEASE GET.FILE.DIRECTORY

   RETURN
END
ROUTINE TO GET.THE.IPEG.INPUTS.FOR.THIS.CASE

   DEFINE TEXT.PTR, LOCATION, LINES, LOAD.FLAG, CHOICE, M, I, LOC, D.TEXT,
      PR.TEXT AS INTEGER VARIABLES
   DEFINE MATCH.FLAG AS AN ALPHA VARIABLE
   DEFINE REFS AS A 1-DIM, INTEGER ARRAY
   DEFINE C.EQPT, C.SQFT, C.DLAB, C.MATS, C.UTIL, C.EL, C.EITCR, C.RLAB,
      C.RUTIL, C.GE, C.P2, C.P3, C.D1, C.D2, C.GF, C.QUAN
      AS SAVED REAL VARIABLES

   DEFINE TM TO MEAN SAVED(29)

   STASH "D" INTO D.TEXT
   STASH "*COMPANY*" INTO PR.TEXT

   ITERATING UNTIL TERMINATED, DO

      ''OBTAIN THE SIZE FROM THE USER
      ITERATING UNTIL TERMINATED, DO
         IF CARD IS NEW
            PRINT 1 LINE THUS
INPUT THE SIZE.INDEX
            START NEW CARD
         ALWAYS

         IF CARD IS NEW  ''USER RESPONDED WITH A BLANK LINE
            IF OLD.SIZE = 0
               PRINT 1 LINE THUS
A BLANK LINE IS NOT AN ACCEPTABLE RESPONSE.
               CYCLE  ''TO ANOTHER ATTEMPT
            OTHERWISE
            LET SIZE = OLD.SIZE
            PRINT 1 LINE WITH SIZE THUS
THE PREVIOUS VALUE ** HAS BEEN ASSUMED.
            LEAVE  ''THE LOOP
         OTHERWISE

         IF MODE IS ALPHA
            NOW CHECK.THE.NEXT.INPUT.WORD.FOR.ABORT
            CHECK.FOR.ABORT
            NOW PUT.THE.NEXT.INPUT.WORD  YIELDING TEXT.PTR
            NOW COMPARE.STRINGS  GIVEN D.TEXT, TEXT.PTR
               YIELDING MATCH.FLAG
            IF MATCH.FLAG NE "M"
               WRITE AS B 1, "THE RESPONSE"
               NOW QUOTE.TEXT  GIVEN TEXT.PTR
               WRITE AS "IS UNACCEPTABLE.", /
               RELEASE TEXT.PTR
               UNTIL CARD IS NEW  ''SKIP REMAINDER OF THIS LINE
                  SKIP 1 FIELD
               CYCLE  ''TO ANOTHER ATTEMPT
            OTHERWISE  ''USER ASKED FOR DEFAULT
            RELEASE TEXT.PTR
            LET SIZE = SIZE.INDEX(F.IPEG.DIRECTORY)
            PRINT 1 LINE WITH SIZE THUS
THE DEFAULT, **, HAS BEEN ASSUMED.
            LEAVE  ''THE LOOP
         OTHERWISE  ''MODE IS NOT ALPHA

         READ SIZE
         LET MATCH.FLAG = "NO.M"
         ITERATING FOR EACH DIRECTORY.ENTRY IN IPEG.DIRECTORY, DO
            IF SIZE = SIZE.INDEX(DIRECTORY.ENTRY)
               LET MATCH.FLAG = "M"
               LEAVE  ''THE LOOP
            OTHERWISE
         REPEAT  ''FOR THE NEXT DIRECTORY.ENTRY
         IF MATCH.FLAG NE "M"
            PRINT 1 LINE WITH SIZE THUS
THE RESPONSE *** IS INVALID AS THIS VALUE IS NOT ON THE FILE.
            UNTIL CARD IS NEW  ''SKIP REMAINDER OF THIS LINE
               SKIP 1 FIELD
            CYCLE  ''TO ANOTHER ATTEMPT
         OTHERWISE
         LEAVE  ''THE LOOP
      REPEAT  ''UNTIL THE USER INPUTS AN ACCEPTABLE SIZE

      ''OBTAIN THE COMPANY.REFERENT FROM THE USER
      ITERATING UNTIL TERMINATED, DO
         IF CARD IS NEW
            PRINT 1 LINE THUS
INPUT THE COMPANY.REFERENT
            START NEW CARD
         ALWAYS

         IF CARD IS NEW  ''USER RESPONDED WITH A BLANK LINE
            IF OLD.COMPANY.REFERENT = 0
               PRINT 1 LINE THUS
A BLANK LINE IS NOT AN ACCEPTABLE RESPONSE.
               CYCLE  ''TO ANOTHER ATTEMPT
            OTHERWISE
            NOW COPY.AN.ARRAY  GIVEN OLD.COMPANY.REFERENT
               YIELDING COMPANY.REFERENT
            WRITE AS B 1, "THE PREVIOUS COMPANY.REFERENT"
            NOW QUOTE.TEXT  GIVEN COMPANY.REFERENT
            WRITE AS "HAS BEEN ASSUMED.", /
            LEAVE  ''THE LOOP
         OTHERWISE

         NOW CHECK.THE.NEXT.INPUT.WORD.FOR.ABORT
         CHECK.FOR.ABORT
         NOW PUT.THE.NEXT.INPUT.WORD  YIELDING TEXT.PTR
         NOW COMPARE.STRINGS  GIVEN D.TEXT, TEXT.PTR
            YIELDING MATCH.FLAG
         IF MATCH.FLAG = "M"  ''USER ASKED FOR DEFAULT
            NOW COPY.AN.ARRAY  GIVEN REFERENCE(F.IPEG.DIRECTORY)
               YIELDING COMPANY.REFERENT
            WRITE AS B 1, "THE DEFAULT"
            NOW QUOTE.TEXT  GIVEN COMPANY.REFERENT
            WRITE AS "HAS BEEN ASSUMED.", /
            RELEASE TEXT.PTR
            LEAVE  ''THE LOOP
         OTHERWISE

         ITERATING FOR EACH DIRECTORY.ENTRY IN IPEG.DIRECTORY, DO
            NOW COMPARE.STRINGS  GIVEN REFERENCE(DIRECTORY.ENTRY), TEXT.PTR
               YIELDING MATCH.FLAG
            IF MATCH.FLAG = "M"
               LEAVE  ''THE LOOP
            OTHERWISE
         REPEAT  ''FOR THE NEXT DIRECTORY.ENTRY
         IF MATCH.FLAG = "M"  ''RESPONSE IS VALID
            STORE TEXT.PTR IN COMPANY.REFERENT
            STORE 0 IN TEXT.PTR
            LEAVE  ''THE LOOP
         OTHERWISE
         WRITE AS B 1, "THE RESPONSE"
         NOW QUOTE.TEXT  GIVEN TEXT.PTR
         WRITE AS "IS INVALID AS IT DOES NOT APPEAR ON THE FILE.", /
         RELEASE TEXT.PTR
         UNTIL CARD IS NEW  ''SKIP REMAINDER OF THIS LINE
            SKIP 1 FIELD
      REPEAT  ''UNTIL THE USER ENTERS AN ACCEPTABLE COMPANY.REFERENT

      NOW DETERMINE.THE.FILE.LOCATION.OF.A.CASE
         GIVEN SIZE, COMPANY.REFERENT
         YIELDING LOCATION, LINES
      IF LOCATION = 0  ''THE CASE IS INVALID
         WRITE SIZE AS B 1,"THE CASE DEFINED BY SIZE =", I 4
         WRITE AS " AND COMPANY.REFERENT"
         NOW QUOTE.TEXT  GIVEN COMPANY.REFERENT
         WRITE AS "IS NOT ON THE FILE.", /
         RELEASE COMPANY.REFERENT
         UNTIL CARD IS NEW  ''SKIP REMAINDER OF THIS LINE
            SKIP 1 FIELD
         CYCLE  ''TO OBTAIN ANOTHER CASE
      OTHERWISE
      LEAVE  ''THE LOOP
   REPEAT  ''UNTIL THE USER INPUTS A VALID CASE

   ''GET THE COMPANY DATA FOR THIS CASE
   LET MATCH.FLAG = "NO.M"
   IF OLD.COMPANY.REFERENT NE 0
      NOW COMPARE.STRINGS  GIVEN OLD.COMPANY.REFERENT, COMPANY.REFERENT
         YIELDING MATCH.FLAG
   ALWAYS
   IF SIZE NE OLD.SIZE OR MATCH.FLAG NE "M"
      USE IPEG.FILE FOR INPUT
      IF IP.FILE.POS = 0 OR IP.FILE.POS > LOCATION
         NOW POSITION.AN.ENTITY.FILE.TO.THE.FIRST.LINE.OF.THE.FIRST.ENTITY
            GIVEN IPEG.FILE, N.IPEG.DIRECTORY
            YIELDING IP.FILE.POS
      ALWAYS
      SKIP LOCATION - IP.FILE.POS RECORDS
      NOW LOAD.THE.COMPANY.DATA
      ''SAVE COMPANY DATA FOR RESTORATION IN A SUBSEQUENT CASE
      LET C.EQPT  = SAVED(1)
      LET C.SQFT  = SAVED(2)
      LET C.DLAB  = SAVED(3)
      LET C.MATS  = SAVED(4)
      LET C.UTIL  = SAVED(5)
      LET C.EL    = SAVED(6)
      LET C.EITCR = SAVED(7)
      LET C.RLAB  = SAVED(13)
      LET C.RUTIL = SAVED(14)
      LET C.GE    = SAVED(27)
      LET C.P2    = SAVED(22)
      LET C.P3    = SAVED(23)
      LET C.D1    = SAVED(24)
      LET C.D2    = SAVED(25)
      LET C.GF    = SAVED(26)
      LET C.QUAN  = P.QUANS
      LET IP.FILE.POS = LOCATION + 14 + TRUNC.F((DIM.F(PROCESS.LIST)-1) / 7)
      USE NORMAL.INPUT.UNIT FOR INPUT
      LET LOAD.FLAG = 1
   ELSE  ''USE COMPANY DATA FROM PREVIOUS CASE - DON'T READ FILE AGAIN
      ''RESTORE THE COMPANY VALUES WHICH MAY HAVE BEEN OVERSTORED
      LET SAVED(1)  = C.EQPT
      LET SAVED(2)  = C.SQFT
      LET SAVED(3)  = C.DLAB
      LET SAVED(4)  = C.MATS
      LET SAVED(5)  = C.UTIL
      LET SAVED(6)  = C.EL
      LET SAVED(7)  = C.EITCR
      LET SAVED(13) = C.RLAB
      LET SAVED(14) = C.RUTIL
      LET SAVED(27) = C.GE
      LET SAVED(22) = C.P2
      LET SAVED(23) = C.P3
      LET SAVED(24) = C.D1
      LET SAVED(25) = C.D2
      LET SAVED(26) = C.GF
      LET P.QUANS = C.QUAN
   ALWAYS

   IF CARD IS NEW
      PRINT 1 LINE THUS
DO YOU WISH TO DISPLAY THE COMPANY DATA?
      START NEW CARD
   ALWAYS
   NOW INTERPRET.THE.NEXT.WORD.IF.NOT.ABORT  GIVEN 1
      YIELDING CHOICE
   CHECK.FOR.ABORT
   IF CHOICE = 1  ''YES
      NOW DISPLAY.THE.COMPANY.DATA
   ALWAYS

   ''OBTAIN THE PROCESS.REFERENT FROM THE USER
   ITERATING UNTIL TERMINATED, DO
      IF CARD IS NEW
         PRINT 1 LINE WITH "*", "*" THUS
INPUT THE PROCESS.REFERENT OR *COMPANY*
         START NEW CARD
      ALWAYS

      IF CARD IS NEW  ''USER RESPONDED WITH A BLANK LINE
         PRINT 1 LINE THUS
A BLANK LINE IS NOT AN ACCEPTABLE RESPONSE.
         CYCLE  ''TO ANOTHER ATTEMPT
      OTHERWISE

      NOW CHECK.THE.NEXT.INPUT.WORD.FOR.ABORT
      CHECK.FOR.ABORT
      NOW PUT.THE.NEXT.INPUT.WORD  YIELDING TEXT.PTR
      NOW COMPARE.STRINGS  GIVEN D.TEXT, TEXT.PTR
         YIELDING MATCH.FLAG
      IF MATCH.FLAG = "M"  ''USER ASKED FOR DEFAULT WHICH IS "*COMPANY*"
         STASH "*COMPANY*" INTO PROCESS.REFERENT
         LET PROCESS.FLAG = 0
         RELEASE TEXT.PTR
         WRITE AS B 1, "THE DEFAULT"
         NOW QUOTE.TEXT  GIVEN PROCESS.REFERENT
         WRITE AS "HAS BEEN ASSUMED.", /
         LEAVE  ''THE LOOP
      OTHERWISE
      NOW COMPARE.STRINGS  GIVEN PR.TEXT, TEXT.PTR
         YIELDING MATCH.FLAG
      IF MATCH.FLAG = "M"
         STORE TEXT.PTR IN PROCESS.REFERENT
         STORE 0 IN TEXT.PTR
         LET PROCESS.FLAG = 0
         LEAVE  ''THE LOOP
      OTHERWISE

      LET M = DIM.F(PROCESS.LIST)
      STORE PROCESS.LIST IN REFS(*)
      ITERATING FOR I = 1 TO M, DO
         NOW COMPARE.STRINGS  GIVEN TEXT.PTR, REFS(I)
            YIELDING MATCH.FLAG
         IF MATCH.FLAG = "M"
            LEAVE  ''THE LOOP
         OTHERWISE
      REPEAT  ''FOR THE NEXT PROCESS
      IF MATCH.FLAG = "M"  ''RESPONSE IS VALID
         STORE TEXT.PTR IN PROCESS.REFERENT
         STORE 0 IN TEXT.PTR
         LET PROCESS.FLAG = 1
         LEAVE  ''THE LOOP
      OTHERWISE
      WRITE AS B 1,"THE RESPONSE"
      NOW QUOTE.TEXT  GIVEN TEXT.PTR
      WRITE AS "IS INVALID AS THIS PROCESS IS NOT IN THE PROCESS.LIST OF"
      NOW QUOTE.TEXT  GIVEN COMPANY.REFERENT
      WRITE AS ".", /
      UNTIL CARD IS NEW  ''SKIP REMAINDER OF THIS LINE
         SKIP 1 FIELD
   REPEAT  ''UNTIL THE USER INPUTS AN ACCEPTABLE PROCESS.REFERENT

   IF PROCESS.FLAG = 1  ''MUST LOAD PROCESS DATA FROM FILE
      LET LOC = LOCATION + 14 + TRUNC.F((M-1)/7) + 6 * (I -1)
      USE IPEG.FILE FOR INPUT
      IF IP.FILE.POS = 0 OR IP.FILE.POS > LOC
         NOW POSITION.AN.ENTITY.FILE.TO.THE.FIRST.LINE.OF.THE.FIRST.ENTITY
            GIVEN IPEG.FILE, N.IPEG.DIRECTORY
            YIELDING IP.FILE.POS
      ALWAYS
      SKIP LOC - IP.FILE.POS RECORDS
      NOW LOAD.THE.PROCESS.DATA
      LET IP.FILE.POS = LOC + 6
      USE NORMAL.INPUT.UNIT FOR INPUT
   ALWAYS

   IF PROCESS.FLAG = 1  ''PROCESS LOADED FROM FILE
      IF CARD IS NEW
         PRINT 1 LINE THUS
DO YOU WISH TO DISPLAY THE PROCESS DATA?
         START NEW CARD
      ALWAYS
      NOW INTERPRET.THE.NEXT.WORD.IF.NOT.ABORT  GIVEN 1
         YIELDING CHOICE
      CHECK.FOR.ABORT
      IF CHOICE = 1  ''YES
         NOW DISPLAY.THE.PROCESS.DATA
      ALWAYS
   ALWAYS

   ''OBTAIN THE REPORT.YEAR FROM THE USER
   ITERATING UNTIL TERMINATED, DO
      IF CARD IS NEW
         PRINT 1 LINE THUS
INPUT THE REPORT.YEAR
         START NEW CARD
      ALWAYS

      IF CARD IS NEW  ''USER RESPONDED WITH A BLANK LINE
         IF OLD.REPORT.YEAR = 0
            PRINT 1 LINE THUS
A BLANK LINE IS NOT AN ACCEPTABLE RESPONSE.
            CYCLE  ''TO ANOTHER ATTEMPT
         OTHERWISE
         LET REPORT.YEAR = OLD.REPORT.YEAR
         PRINT 1 LINE WITH REPORT.YEAR THUS
THE PREVIOUS VALUE **** HAS BEEN ASSUMED.
         LEAVE  ''THE LOOP
      OTHERWISE

      IF MODE IS ALPHA
         NOW CHECK.THE.NEXT.INPUT.WORD.FOR.ABORT
         CHECK.FOR.ABORT
         NOW PUT.THE.NEXT.INPUT.WORD  YIELDING TEXT.PTR
         NOW COMPARE.STRINGS  GIVEN D.TEXT, TEXT.PTR
            YIELDING MATCH.FLAG
         IF MATCH.FLAG NE "M"
            WRITE AS B 1,"THE RESPONSE"
            NOW QUOTE.TEXT  GIVEN TEXT.PTR
            WRITE AS "IS UNACCEPTABLE.", /
            RELEASE TEXT.PTR
            UNTIL CARD IS NEW  ''SKIP REMAINDER OF THIS LINE
            SKIP 1 FIELD
            CYCLE  ''TO ANOTHER ATTEMPT
         OTHERWISE  ''USER ASKED FOR DEFAULT
         RELEASE TEXT.PTR
         LET REPORT.YEAR = TB
         PRINT 1 LINE WITH REPORT.YEAR THUS
THE DEFAULT, ****, HAS BEEN ASSUMED.
         LEAVE  ''THE LOOP
      OTHERWISE  ''MODE IS NOT ALPHA

      READ REPORT.YEAR
      IF REAL.F(REPORT.YEAR) ) TB OR REAL.F(REPORT.YEAR) > TM
         PRINT 2 LINES WITH REPORT.YEAR, TB, TM THUS
YOUR RESPONSE **** IS OUTSIDE THE RANGE ****. TO ****.
DO YOU WISH TO RETAIN IT ANYWAY?
         NOW INTERPRET.THE.NEXT.WORD.IF.NOT.ABORT  GIVEN 1
            YIELDING CHOICE
         CHECK.FOR.ABORT
         IF CHOICE = 1  ''YES
            LEAVE  ''THE LOOP
         OTHERWISE
         CYCLE  ''TO ANOTHER ATTEMPT
      OTHERWISE
      LEAVE  ''THE LOOP
   REPEAT  ''UNTIL THE USER INPUTS A VALID REPORT.YEAR

   RELEASE D.TEXT, PR.TEXT
   RETURN

   'ABORT'  ''HERE IF USER ENTERS ABORT

      RELEASE D.TEXT, PR.TEXT
      RELEASE COMPANY.REFERENT, PROCESS.REFERENT
      RELEASE PROCESS.DESCRIPTIVE.NAME
      IF LOAD.FLAG = 1
         RELEASE COMPANY.DESCRIPTIVE.NAME, INDUSTRY.PRODUCTION.UNITS,
            PROCESS.PRODUCT.UNITS
         NOW RELEASE.A.TEXT.VECTOR  GIVEN PROCESS.LIST
         STORE 0 IN PROCESS.LIST
         LET P.QUAN = 0.0
         LET I.QUAN = 0.0
         FOR I = 1 TO N.VARIABLES,
            LET SAVED(I) = 0.0
         RELEASE OLD.COMPANY.REFERENT
         STORE 0 IN OLD.COMPANY.REFERENT
      ALWAYS

      RETURN
END
ROUTINE TO DISPLAY.THE.INDEPENDENT.VARIABLES
   GIVEN VARIABLES

   DEFINE VARIABLES, VARIABLE.NUMBER, I AS INTEGER VARIABLES

   IF CARD IS NEW
      PRINT 1 LINE THUS
INPUT THE LIST OF VARIABLES TO BE DISPLAYED
      START NEW CARD
   ALWAYS

   SKIP 2 LINES
   ITERATING UNTIL TERMINATED, DO
      NOW INTERPRET.THE.USERS.NEXT.WORD  GIVEN 2, 1
         YIELDING VARIABLE.NUMBER

      IF VARIABLE.NUMBER ) 0  ''EMPTY REMAINING LINE SO QUIT
         RETURN
      OTHERWISE

      IF VARIABLE.NUMBER = 0  ''ALL
         FOR I = 1 TO N.VARIABLES,
            NOW LIST.AN.INDEPENDENT.VARIABLE  GIVEN VARIABLES, I
         RETURN
      OTHERWISE

      IF VARIABLE.NUMBER = N.VARIABLES + 1  ''I.QUAN
         WRITE AS B 1, "I.QUAN = "
         NOW WRITE.A.REAL.VALUE  GIVEN I.QUANS, 5
         WRITE AS S 1
         NOW PRINT.TEXT  GIVEN INDUSTRY.PRODUCTION.UNITS
         WRITE AS /
         CYCLE
      OTHERWISE

      IF VARIABLE.NUMBER = N.VARIABLES + 2  ''P.QUAN
         WRITE AS B 1, "P.QUAN = "
         NOW WRITE.A.REAL.VALUE  GIVEN P.QUANS, 5
         WRITE AS S 1
         NOW PRINT.TEXT  GIVEN PROCESS.PRODUCT.UNITS
         WRITE AS /
         CYCLE
      OTHERWISE

      NOW LIST.AN.INDEPENDENT.VARIABLE  GIVEN VARIABLES, VARIABLE.NUMBER

   REPEAT  ''UNTIL TERMINATED

END
ROUTINE TO LIST.AN.INDEPENDENT.VARIABLE
   GIVEN VARIABLES, VARIABLE.NUMBER

   DEFINE VARIABLE.NUMBER AS AN INTEGER VARIABLE
   DEFINE VARIABLES AS A 1-DIM, REAL ARRAY

   WRITE AS B 1
   NOW PRINT.TEXT  GIVEN IVNAMES(VARIABLE.NUMBER)
   WRITE AS " = "
   NOW WRITE.A.REAL.VALUE  GIVEN VARIABLES(VARIABLE.NUMBER), 5
   WRITE AS S 1
   NOW PRINT.TEXT  GIVEN IVUNITS(VARIABLE.NUMBER)
   WRITE AS /

   RETURN
END
ROUTINE TO DETERMINE.THE.FILE.LOCATION.OF.A.CASE
   GIVEN SIZE, REF
   YIELDING LOCATION, LINES

   DEFINE SIZE, REF, LOCATION, LINES AS INTEGER VARIABLES
   DEFINE MATCH.FLAG AS AN ALPHA VARIABLE

   LET LOCATION = 0
   LET LINES = 0
   ITERATING FOR EACH DIRECTORY.ENTRY IN IPEG.DIRECTORY, DO
      NOW COMPARE.STRINGS  GIVEN REF, REFERENCE(DIRECTORY.ENTRY)
         YIELDING MATCH.FLAG
      IF SIZE = SIZE.INDEX(DIRECTORY.ENTRY) AND MATCH.FLAG = "M"
         ADD N.IPEG.DIRECTORY + 2 TO LOCATION
         LET LINES = LINES.OF.DATA(DIRECTORY.ENTRY)
         RETURN
      OTHERWISE
      ADD LINES.OF.DATA(DIRECTORY.ENTRY) TO LOCATION
   REPEAT  ''FOR THE NEXT DIRECTORY.ENTRY

   LET LOCATION = 0  ''SINCE CASE IS NOT ON THE FILE

   RETURN
END
ROUTINE TO LOAD.THE.COMPANY.DATA

   DEFINE I AS AN INTEGER VARIABLE

   ''DESTROY ANY OLD COMPANY DATA FIRST
   RELEASE COMPANY.DESCRIPTIVE.NAME, INDUSTRY.PRODUCTION.UNITS,
      PROCESS.PRODUCT.UNITS
   NOW RELEASE.A.TEXT.VECTOR  GIVEN PROCESS.LIST
   STORE 0 IN PROCESS.LIST
   LET I.QUANS = 0.0
   LET P.QUANS = 0.0
   FOR I = 1 TO N.VARIABLES,
      LET SAVED(I) = 0.0

   SKIP 1 RECORD  ''TO SKIP OVER THE FIRST LINE
   NOW READ.A.LINE.OF.TEXT  YIELDING COMPANY.DESCRIPTIVE.NAME
   NOW READ.A.TEXT.VECTOR.FROM.FILE  YIELDING PROCESS.LIST
   FOR I = 1 TO 5,
      READ SAVED(I)
   READ I.QUANS, P.QUANS
   NOW READ.A.LINE.OF.TEXT  YIELDING INDUSTRY.PRODUCTION.UNITS
   NOW READ.A.LINE.OF.TEXT  YIELDING PROCESS.PRODUCT.UNITS
   FOR I = 6 TO 31,
      READ SAVED(I)
   READ TB
   FOR I = 32 TO N.VARIABLES,
      READ SAVED(I)
   IF DATA IS NOT ENDED
      START NEW RECORD
   ALWAYS

   RETURN
END
ROUTINE TO DISPLAY.THE.COMPANY.DATA

   DEFINE I AS AN INTEGER VARIABLE

   SKIP 2 LINES
   WRITE AS B 1, "COMPANY: "
   NOW PRINT.TEXT  GIVEN COMPANY.REFERENT
   WRITE AS ", "
   NOW MOVE.TEXT  GIVEN COMPANY.DESCRIPTIVE.NAME, 0, 0
   WRITE AS /

   WRITE AS "PROCESS.LIST =", /
   NOW WRITE.A.TEXT.VECTOR  GIVEN PROCESS.LIST
   SAY "I.QUAN = "
   NOW WRITE.A.REAL.VALUE  GIVEN I.QUANS, 5
   WRITE AS S 1
   NOW PRINT.TEXT  GIVEN INDUSTRY.PRODUCTION.UNITS
   WRITE AS /
   SAY "P.QUAN = "
   NOW WRITE.A.REAL.VALUE  GIVEN P.QUANS, 5
   WRITE AS S 1
   NOW PRINT.TEXT  GIVEN PROCESS.PRODUCT.UNITS
   WRITE AS /
   SAY "TB = "
   NOW WRITE.A.REAL.VALUE  GIVEN TB, 5
   WRITE AS /
   SKIP 1 LINE
   FOR I = 1 TO N.VARIABLES,
      NOW LIST.AN.INDEPENDENT.VARIABLE  GIVEN SAVED(*), I

   RETURN
END
ROUTINE TO LOAD.THE.PROCESS.DATA

   DEFINE I AS AN INTEGER VARIABLE

   RELEASE PROCESS.DESCRIPTIVE.NAME, PROCESS.PRODUCT.UNITS
   SKIP 1 RECORD  ''TO SKIP OVER THE FIRST LINE
   NOW READ.A.LINE.OF.TEXT  YIELDING PROCESS.DESCRIPTIVE.NAME
   FOR I = 1 TO 5,
      READ SAVED(I)
   READ SAVED(13)   ''RLAB
   READ SAVED(14)   ''RUTIL
   READ SAVED(27)   ''GE
   READ SAVED(22)   ''P2
   READ SAVED(23)   ''P3
   READ SAVED(24)   ''D1
   READ SAVED(25)   ''D2
   READ SAVED(26)   ''GF
   READ P.QUANS      ''DESTROYS COMPANY VALUE
   READ SAVED(6)   ''EL
   READ SAVED(7)   ''EITCR
   NOW READ.A.LINE.OF.TEXT  YIELDING PROCESS.PRODUCT.UNITS
   IF DATA IS NOT ENDED
      START NEW RECORD
   ALWAYS

   RETURN
END
ROUTINE TO DISPLAY.THE.PROCESS.DATA

   DEFINE I AS AN INTEGER VARIABLE

   IF PROCESS.FLAG = 0  ''THERE IS NO PROCESS DATA
      SKIP 2 LINES
      WRITE AS B 1,"THERE IS NO PROCESS DATA AVAILABLE FOR PROCESS"
      NOW QUOTE.TEXT  GIVEN PROCESS.REFERENT
      WRITE AS /
      RETURN
   OTHERWISE

   SKIP 2 LINES
   WRITE AS B 1,"PROCESS: "
   NOW PRINT.TEXT  GIVEN PROCESS.REFERENT
   WRITE AS ", "
   NOW MOVE.TEXT  GIVEN PROCESS.DESCRIPTIVE.NAME, 0, 0
   WRITE AS /
   SKIP 1 LINE
   FOR I = 1 TO 7,
      NOW LIST.AN.INDEPENDENT.VARIABLE  GIVEN SAVED(*), I
   NOW LIST.AN.INDEPENDENT.VARIABLE  GIVEN SAVED(*), 13
   NOW LIST.AN.INDEPENDENT.VARIABLE  GIVEN SAVED(*), 14
   NOW LIST.AN.INDEPENDENT.VARIABLE  GIVEN SAVED(*), 27
   FOR I = 22 TO 26,
      NOW LIST.AN.INDEPENDENT.VARIABLE  GIVEN SAVED(*), I
   SAY "P.QUAN = "
   NOW WRITE.A.REAL.VALUE  GIVEN P.QUANS, 5
   WRITE AS S 1
   NOW PRINT.TEXT  GIVEN PROCESS.PRODUCT.UNITS
   WRITE AS /

   RETURN
END
ROUTINE TO CALCULATE.IPEG.COEFFICIENTS

   DEFINE A, CONSTANT, S1, S2, S3, S4 AS REAL VARIABLES
   DEFINE I AS AN INTEGER VARIABLE

   LET VD = 1.0 + RLAB.P
   LET VS = RUTIL.P
   LET Q = D1.P
   LET Y = TS.P + TC.P
   IF Y = 0.0
      LET TCC = TM.P
   ELSE
      LET S4 = TM.P + 1.0 - Y
      IF FRAC.F(S4) > .999
         LET TCC = 1 + TRUNC.F(S4)
      ELSE
         LET TCC = TRUNC.F(S4)
      ALWAYS
   ALWAYS
   LET K = (R.P + (IR.P * (LAMBDA.P - 1.0) * (1.0 - TAU.P))) / LAMBDA.P
   LET CAPK = (K - G.P) / (1.0 + G.P)
   LET A = (1.0 + CAPK) ** (-CRT.P)
   LET GCRF = CAPK / (1.0 - A)
   LET F1 = TRUNC.F((FL.P -1.0) / 2.0)
   LET B1 = P1.P * D1.P + P2.P * D2.P + P3.P
   LET TSU = TM.P - TS.P
   LET TEC = TSU
   LET PHI = (1.0 + G.P) ** (-TS.P)
   LET YE = TS.P
   LET DFE = PHI
   LET S1 = 1.0 - X.P
   LET CONSTANT = S1 * (1.0 - TAU.P)

   NOW CALCULATE.INTERMEDIATE.VARIABLES

   LET S2 = GCRF / CONSTANT
   LET S3 = 1.0 - PVSUCD * S2
   FOR I = 1 TO 5,
      LET C(I) =((OPR(I)+ OTX(I) + INS(I) + INT(I) + RPL(I) + Z * BVAL(I)) /S1
         + ((EQR(I) - ITC(I)) / CONSTANT)
         + (S2 * (PVELP(I) + PVECC(I) + PVITC(I) + PVDEP(I) + PVEWC(I)
         + PVSUCI(I)))) / S3
   RETURN
END
ROUTINE TO CALCULATE.INTERMEDIATE.VARIABLES

   DEFINE I AS AN INTEGER VARIABLE
   DEFINE S1, S2, S3, S4, S5, C, D, H1 AS REAL VARIABLES

   LET S1 = 1.0 + XOPR.P
   LET S2 = 1.0 + XEC.P
   LET S3 = 1.0 - TAU.P

   LET OPR(2) = S1 * VS
   LET OPR(3) = S1 * VD
   LET OPR(4) = S1
   LET OPR(5) = S1

   LET FAC(2) = B1 * (1.0 + XFC.P)

   FOR I = 1 TO 5,
      LET WCAP(I) = W.P * OPR(I)

   LET RPL(1) = S2 / EL.P
   LET RPL(2) = FAC(2) / FL.P

   LET OTX(1) = .5 * BETA.P * S2
   LET OTX(2) = BETA.P * (.5 * FAC(2) + WCAP(2))
   LET OTX(3) = BETA.P * WCAP(3)
   LET OTX(4) = BETA.P * WCAP(4)
   LET OTX(5) = OTX(4)

   LET BVAL(1) = .5 * S2
   LET BVAL(2) = .5 * FAC(2)

   LET INS(1) = NU.P * S2
   LET INS(2) = NU.P * (FAC(2) + WCAP(2))
   LET INS(3) = NU.P * WCAP(3)
   LET INS(4) = NU.P * WCAP(4)
   LET INS(5) = INS(4)

   LET C = (LAMBDA.P - 1.0) * IR.P / LAMBDA.P
   LET INT(1) = C * BVAL(1)
   LET INT(2) = C * (BVAL(2) + WCAP(2))
   LET INT(3) = C * WCAP(3)
   LET INT(4) = C * WCAP(4)
   LET INT(5) = INT(4)

   LET D = R.P / LAMBDA.P
   LET EQR(1) = D * BVAL(1)
   LET EQR(2) = D * (BVAL(2) + WCAP(2))
   LET EQR(3) = D * WCAP(3)
   LET EQR(4) = D * WCAP(4)
   LET EQR(5) = EQR(4)

   LET ITC(1) = RITCE * S2 / EL.P

   IF Y LE 0.0
      LET PVELP(2) = 0.0
   ELSE  ''Y > 0.0
      LET C = (1.0 + K) ** Y - 1.0
      IF Y ) 1.0
         LET PVELP(2) = P1.P * Q * C
      ELSE  ''Y GE 1.0
         IF K = 0.0
            LET PVELP(2) = P1.P * Q * BETA.P * (Y - 1.0)
         ELSE  ''K NE 0.0
            LET PVELP(2) = P1.P * Q * (C * (1.0 + BETA.P / K) - BETA.P)
         ALWAYS
      ALWAYS
   ALWAYS

   NOW CALCULATE.PVECC

   LET PVITC(1) = -(S2 * DFE * A.P * (1.0 + K) ** YE)

   NOW CALCULATE.PVDEP
   NOW CALCULATE.PVEWC

   LET H1 = (1.0 + K) ** TS.P
   LET PVSUCD = PHI * H1 * S3 * (TS.P * (X.P -L.P) + W.P)

   LET S4 = PHI * H1 * TS.P
   LET S5 = N.P * L.P -1.0
   LET PVSUCI(1) = S4 * (EQR(1) + S3 * (.5 * Z.P * S2 + RPL(1) + INS(1)
      + OTX(1) + INT(1)))
   LET PVSUCI(2) = S4 * (EQR(2) + S3 * (.5 * Z.P * FAC(2) + OPR(2) + RPL(2)
      + INS(2) + OTX(2) + INT(2)))
   LET PVSUCI(3) = S4 * (EQR(3) + S3 * (OPR(3) + INS(3) + OTX(3) + INT(3)))
   LET PVSUCI(4) = S4 * (EQR(4) + S3 * (S5 + OPR(4) + INS(4) + OTX(4)
      + INT(4)))
   LET PVSUCI(5) = S4 * (EQR(5) + S3 * (S5 + OPR(5) + INS(5) + OTX(5)
      + INT(5)))

   RETURN
END
ROUTINE TO CALCULATE.PVECC

   DEFINE YF, DFF, CONSTANT, D, S1, S2, S3, J, Y2, Y3 AS REAL VARIABLES

   LET YF = TM.P - TCC
   LET S1 = 1.0 + K
   LET S2 = 1.0 + G.P
   LET S3 = 1.0 + GF.P
   LET DFF = S3 ** (-YF)
   LET CONSTANT = S1 ** YF
   LET D = S1 ** YE

   FOR J = (TEC + 1.0) TO (TM.P - 1.0),
      ADD S1 ** (TM.P - J) * S2 ** (J - TEC) TO Y2
   FOR J = (TCC + 1.0) TO (TM.P - 1.0),
      ADD S1 ** (TM.P - J) * S3 ** (J - TCC) TO Y3

   LET PVECC(1) = (1.0 + XEC.P) * DFE * ((D - 1.0) + NU.P * D
      + (NU.P + BETA.P) * Y2)

   LET PVECC(2) = (1.0 + XFC.P) * DFF * B1 * ((CONSTANT - 1.0) + NU.P
      * CONSTANT + Y3 * (NU.P + BETA.P))

   RETURN
END
ROUTINE TO CALCULATE.PVDEP

   DEFINE S1, S2, S3, S4, C, J, Y4, Y5 AS REAL VARIABLES

   LET S1 = (1.0 + GE.P) / (1.0 + K)
   LET S2 = 2.0 / EL.P
   LET S3 = 2.0 / FL.P
   LET S4 = (1.0 + GF.P) / (1.0 + K)
   LET C = S1 ** EL.P

   FOR J = 0.0 TO (EL.P - 1.0),
      ADD (1.0 - S2 * J) * S1 ** J TO Y4
   FOR J = 0.0 TO F1,
      ADD (1.0 - S3 * J) * S4 ** J TO Y5

   LET PVDEP(1) = ((BETA.P + K) * Y4 * (1.0 + XEC.P)) / (2.0 * (1.0 - C))
   LET PVDEP(2) = .5 * (BETA.P + K) * B1 * Y5 * (1.0 + XFC.P)

   RETURN
END
ROUTINE TO CALCULATE.PVEWC

   DEFINE S1, S2, DF, J, Y6, Y7, H AS REAL VARIABLES

   LET S1 = 1.0 + K
   LET S2 = 1.0 + G.P
   LET DF = S2 ** (-TS.P)

   FOR J = 1.0 TO (TS.P - 1.0),
      ADD S2 ** (J - 1.0) * (S1 ** (TS.P - J) - 1.0) TO Y6
   FOR J = 1.0 TO TS.P,
      ADD (NU.P * S2 ** J + BETA.P * S2 ** (J -1.0)) * S1 ** (TS.P - J) TO Y7

   LET H = (1.0 + NU.P) * S1 ** TS.P - 1.0 + G.P * Y6 + Y7

   LET PVEWC(4) = H * DF * W.P * (1.0 + XOPR.P)
   LET PVEWC(5) = PVEWC(4)
   LET PVEWC(2) = PVEWC(4) * VS
   LET PVEWC(3) = PVEWC(4) * VD

   RETURN
END
ROUTINE TO INITIALIZE.VARIABLE.NAMES.MIN.MAX.AND.DEFAULT.VALUES

   DEFINE I AS AN INTEGER VARIABLE

   RESERVE IVNAMES(*) AS N.VARIABLES

   STASH "EQPT"    INTO IVNAMES(1)
   STASH "SQFT"    INTO IVNAMES(2)
   STASH "DLAB"    INTO IVNAMES(3)
   STASH "MATS"    INTO IVNAMES(4)
   STASH "UTIL"    INTO IVNAMES(5)
   STASH "EL"      INTO IVNAMES(6)
   STASH "EITCR"   INTO IVNAMES(7)
   STASH "FL"      INTO IVNAMES(8)
   STASH "BETA"    INTO IVNAMES(9)
   STASH "X"       INTO IVNAMES(10)
   STASH "NU"      INTO IVNAMES(11)
   STASH "Z"       INTO IVNAMES(12)
   STASH "RLAB"    INTO IVNAMES(13)
   STASH "RUTIL"   INTO IVNAMES(14)
   STASH "G"       INTO IVNAMES(15)
   STASH "W"       INTO IVNAMES(16)
   STASH "TAU"     INTO IVNAMES(17)
   STASH "LAMBDA"  INTO IVNAMES(18)
   STASH "IR"      INTO IVNAMES(19)
   STASH "R"       INTO IVNAMES(20)
   STASH "P1"      INTO IVNAMES(21)
   STASH "P2"      INTO IVNAMES(22)
   STASH "P3"      INTO IVNAMES(23)
   STASH "D1"      INTO IVNAMES(24)
   STASH "D2"      INTO IVNAMES(25)
   STASH "GF"      INTO IVNAMES(26)
   STASH "GE"      INTO IVNAMES(27)
   STASH "TS"      INTO IVNAMES(28)
   STASH "TM"      INTO IVNAMES(29)
   STASH "TC"      INTO IVNAMES(30)
   STASH "L"       INTO IVNAMES(31)
   STASH "A"       INTO IVNAMES(32)
   STASH "UF"      INTO IVNAMES(33)
   STASH "LF"      INTO IVNAMES(34)
   STASH "T"       INTO IVNAMES(35)
   STASH "M"       INTO IVNAMES(36)
   STASH "B"       INTO IVNAMES(37)
   STASH "TLF"     INTO IVNAMES(38)
   STASH "XEC"     INTO IVNAMES(39)
   STASH "XFC"     INTO IVNAMES(40)
   STASH "XOPR"    INTO IVNAMES(41)
   STASH "N"       INTO IVNAMES(42)
   STASH "CRT"     INTO IVNAMES(43)

   RESERVE IVUNITS(*) AS N.VARIABLES

   STASH "$"            INTO IVUNITS(1)
   STASH "SQ. FT."      INTO IVUNITS(2)
   STASH "$/YEAR"       INTO IVUNITS(3)
   STASH "$/YEAR"       INTO IVUNITS(4)
   STASH "$/YEAR"       INTO IVUNITS(5)
   STASH "YEARS"        INTO IVUNITS(6)
   STASH "FRACTION/YR"  INTO IVUNITS(7)
   STASH "YEARS"        INTO IVUNITS(8)
   STASH "FRACTION/YR"  INTO IVUNITS(9)
   STASH "FRACTION/YR"  INTO IVUNITS(10)
   STASH "FRACTION/YR"  INTO IVUNITS(11)
   STASH "FRACTION/YR"  INTO IVUNITS(12)
   STASH "$/$"          INTO IVUNITS(13)
   STASH "$/SQ. FT."    INTO IVUNITS(14)
   STASH "FRACTION/YR"  INTO IVUNITS(15)
   STASH "YEARS"        INTO IVUNITS(16)
   STASH "FRACTION/YR"  INTO IVUNITS(17)
   STASH "$/$"          INTO IVUNITS(18)
   STASH "FRACTION/YR"  INTO IVUNITS(19)
   STASH "FRACTION/YR"  INTO IVUNITS(20)
   STASH "$/SQ. FT."    INTO IVUNITS(21)
   STASH "$/SQ. FT."    INTO IVUNITS(22)
   STASH "$/SQ. FT."    INTO IVUNITS(23)
   STASH "FRACTION"     INTO IVUNITS(24)
   STASH "FRACTION"     INTO IVUNITS(25)
   STASH "FRACTION/YR"  INTO IVUNITS(26)
   STASH "FRACTION/YR"  INTO IVUNITS(27)
   STASH "YEARS"        INTO IVUNITS(28)
   STASH "YEAR"         INTO IVUNITS(29)
   STASH "YEARS"        INTO IVUNITS(30)
   STASH "FRACTION/YR"  INTO IVUNITS(31)
   STASH "FRACTION/YR"  INTO IVUNITS(32)
   STASH "FRACTION/YR"  INTO IVUNITS(33)
   STASH "FRACTION/YR"  INTO IVUNITS(34)
   STASH "YEARS"        INTO IVUNITS(35)
   STASH "YEARS"        INTO IVUNITS(36)
   STASH "YEARS"        INTO IVUNITS(37)
   STASH "FRACTION/YR"  INTO IVUNITS(38)
   STASH "FRACTION/YR"  INTO IVUNITS(39)
   STASH "FRACTION/YR"  INTO IVUNITS(40)
   STASH "FRACTION/YR"  INTO IVUNITS(41)
   STASH "FRACTION"     INTO IVUNITS(42)
   STASH "YEARS"        INTO IVUNITS(43)

   RESERVE VMIN(*), VMAX(*), VDEF(*) AS N.VARIABLES

   FOR I = 1 TO N.VARIABLES,
      LET VDEF(I) = -RINF.C

   FOR I = 1 TO 5,
      LET VMAX(I) = 10.0 ** 9.0
   LET VMAX(6) = 50.0
   LET VMAX(7) = 1.0
   LET VMAX(8) = 100.0
   LET VMAX(9) = 1.0
   LET VMAX(10) = 1.0
   LET VMAX(11) = 1.0
   LET VMAX(12) = 1.0
   LET VMAX(13) = 500.0
   LET VMAX(14) = 1000.0
   LET VMAX(15) = 1.0
   LET VMAX(16) = 1000.0
   LET VMAX(17) = 1.0
   LET VMAX(18) = 100.0
   LET VMAX(19) = 1.0
   LET VMAX(20) = 1.0
   LET VMAX(21) = 5.0
   LET VMAX(22) = 1000.0
   LET VMAX(23) = 500.0
   LET VMAX(24) = 1000.0
   LET VMAX(25) = 1000.0
   LET VMAX(26) = 1.0
   LET VMAX(27) = 1.0
   LET VMAX(28) = 25.0
   LET VMAX(29) = 2000.0
   LET VMAX(30) = 25.0
   LET VMAX(31) = 1.0
   LET VMAX(32) = 1.0
   LET VMAX(33) = 1.0
   LET VMAX(34) = 1.0
   LET VMAX(35) = 20.0
   LET VMAX(36) = 10.0
   LET VMAX(37) = 5.0
   LET VMAX(38) = 1.0
   LET VMAX(39) = 1.0
   LET VMAX(40) = 1.0
   LET VMAX(41) = 1.0
   LET VMAX(42) = 10.0
   LET VMAX(43) = RINF.C

   LET VMIN(6) = 1.0
   LET VMIN(8) = 1.0
   LET VMIN(19) = .01
   LET VMIN(43) = 2.0
   LET VMIN(18) = 1.0
   LET VMIN(29) = 1950.0

   RESERVE VNAMES(*) AS 23

   STASH "C(1)"    INTO VNAMES(1)
   STASH "C(2)"    INTO VNAMES(2)
   STASH "C(3)"    INTO VNAMES(3)
   STASH "C(4)"    INTO VNAMES(4)
   STASH "C(5)"    INTO VNAMES(5)
   STASH "PRICE"   INTO VNAMES(6)
   STASH "PRICE"   INTO VNAMES(7)
   STASH "OPR"     INTO VNAMES(8)
   STASH "OTX"     INTO VNAMES(9)
   STASH "BVAL"    INTO VNAMES(10)
   STASH "INS"     INTO VNAMES(11)
   STASH "INT"     INTO VNAMES(12)
   STASH "RPL"     INTO VNAMES(13)
   STASH "ITC"     INTO VNAMES(14)
   STASH "EQR"     INTO VNAMES(15)
   STASH "WCAP"    INTO VNAMES(16)
   STASH "FAC"     INTO VNAMES(17)
   STASH "PVELP"   INTO VNAMES(18)
   STASH "PVECC"   INTO VNAMES(19)
   STASH "PVITC"   INTO VNAMES(20)
   STASH "PVEWC"   INTO VNAMES(21)
   STASH "PVDEP"   INTO VNAMES(22)
   STASH "PVSUCI"  INTO VNAMES(23)

   RELEASE INITIALIZE.VARIABLE.NAMES.MIN.MAX.AND.DEFAULT.VALUES

   RETURN
END
ROUTINE TO DISPLAY.THE.CHANGED.VARIABLES

   DEFINE I, FLAG AS INTEGER VARIABLES

   ITERATING FOR I = 1 TO N.VARIABLES, DO
      IF SAVED(I) NE WORKING(I)
         LET FLAG = 1
         LEAVE  ''THE LOOP
      OTHERWISE
   REPEAT  ''FOR NEXT I

   IF I.QUAN NE I.QUANS OR P.QUAN NE P.QUANS
      LET FLAG = 1
   ALWAYS

   IF FLAG = 0
      RETURN
   OTHERWISE

   SKIP 1 LINE
   PRINT 4 LINES THUS
THE FOLLOWING VARIABLES HAVE WORKING VALUES DIFFERENT THAN SAVED VALUES:

 VARIABLE      SAVED VALUE   WORKING VALUE
 --------      -----------   -------------

   ITERATING FOR I = 1 TO N.VARIABLES, DO
      IF SAVED(I) = WORKING(I)
         CYCLE  ''TO THE NEXT I
      OTHERWISE
      WRITE AS B 2
      NOW PRINT.TEXT  GIVEN IVNAMES(I)
      WRITE AS B 16
      NOW WRITE.A.REAL.VALUE  GIVEN SAVED(I), 5
      WRITE AS B 31
      NOW WRITE.A.REAL.VALUE  GIVEN WORKING(I), 5
      WRITE AS /
   REPEAT  ''FOR THE NEXT I

   IF I.QUAN NE I.QUANS
      WRITE AS B 2, "I.QUAN", B 16
      NOW WRITE.A.REAL.VALUE  GIVEN I.QUANS, 5
      WRITE AS B 31
      NOW WRITE.A.REAL.VALUE  GIVEN I.QUAN, 5
      WRITE AS /
   ALWAYS

   IF P.QUAN NE P.QUANS
      WRITE AS B 2, "P.QUAN", B 16
      NOW WRITE.A.REAL.VALUE  GIVEN P.QUANS, 5
      WRITE AS B 31
      NOW WRITE.A.REAL.VALUE  GIVEN P.QUAN, 5
      WRITE AS /
   ALWAYS

   RETURN
END
ROUTINE TO CHANGE.WORKING.VARIABLES

   DEFINE CHOICE AS AN INTEGER VARIABLE

   ITERATING UNTIL TERMINATED, DO
      IF CARD IS NEW
         PRINT 1 LINE THUS
INPUT A CHANGE COMMAND OR DONE
         START NEW CARD
      ALWAYS

      NOW INTERPRET.THE.NEXT.WORD.IF.NOT.ABORT  GIVEN 4
         YIELDING CHOICE
      IF ABORT.FLAG = 1  ''(ON)
         SAY "***** YOUR CHANGE COMMAND HAS BEEN ABORTED.", /
         SKIP 1 LINE
         LET ABORT.FLAG = 0
         CYCLE  ''TO ANOTHER ATTEMPT
      OTHERWISE

      IF CHOICE = 2  ''(DONE)
         RETURN
      OTHERWISE

      NOW INTERPRET.THE.NEXT.WORD.IF.NOT.ABORT  GIVEN 2
         YIELDING CHOICE
      IF ABORT.FLAG = 1  ''(ON)
         SAY "***** YOUR CHANGE COMMAND HAS BEEN ABORTED.", /
         SKIP 1 LINE
         LET ABORT.FLAG = 0
         CYCLE  ''TO ANOTHER ATTEMPT
      OTHERWISE

      IF CHOICE = N.VARIABLES + 1  ''I.QUAN
         NOW CHANGE.A.REAL  GIVEN I.QUAN, -RINF.C, .001, 10.0 ** 10.0
            YIELDING I.QUAN
         LET ABORT.FLAG = 0
         CYCLE
      OTHERWISE

      IF CHOICE = N.VARIABLES + 2  ''P.QUAN
         NOW CHANGE.A.REAL  GIVEN P.QUAN, -RINF.C, .001, 10.0 ** 10.0
            YIELDING P.QUAN
         LET ABORT.FLAG = 0
         CYCLE
      OTHERWISE

      NOW CHANGE.A.REAL  GIVEN WORKING(CHOICE), VDEF(CHOICE),
         VMIN(CHOICE), VMAX(CHOICE)
         YIELDING WORKING(CHOICE)
      LET ABORT.FLAG = 0

   REPEAT  ''UNTIL TERMINATED WITH "DONE"

   RETURN
END
ROUTINE TO OBTAIN.THE.INDEPENDENT.VARIABLE.AND.VALUES

   DEFINE FORM, FLAG, I, CHOICE, NMAX AS INTEGER VARIABLES
   DEFINE XS, XE, DELTAX, LAMDA AS REAL VARIABLES
   DEFINE VALUES, MIN.VALUES, MAX.VALUES AS 1-DIM, REAL ARRAYS

   IF CARD IS NEW
      PRINT 1 LINE THUS
INPUT AN INDEPENDENT VARIABLE FOR THE SENSITIVITY STUDY
      START NEW CARD
   ALWAYS
   NOW INTERPRET.THE.NEXT.WORD.IF.NOT.ABORT  GIVEN 2
      YIELDING IVINDEX
   CHECK.FOR.ABORT

   IF IVINDEX = 0  ''USER WANTS A SINGLE COMPUTATION NOT SENSITIVITY STUDY
      RETURN
   OTHERWISE

   ''GET THE FORM NUMBER
   IF CARD IS NEW
      PRINT 1 LINE THUS
INPUT THE FORM OF THE INDEPENDENT VARIABLE SPECIFICATION
      START NEW CARD
   ALWAYS
   NOW READ.AN.INTEGER  GIVEN 1, 1, 4, 1  YIELDING FORM
   CHECK.FOR.ABORT

   LET NMAX = 1000
   RESERVE MIN.VALUES(*), MAX.VALUES(*) AS 1
   LET MIN.VALUES(1) = VMIN(IVINDEX)
   LET MAX.VALUES(1) = VMAX(IVINDEX)

   ''GET THE SET OF VALUES ACCORDING TO FORM
   ITERATING UNTIL TERMINATED, DO

      SELECT CASE(FORM)'

      CASE(1)'  ''FORM 1  X(I) I = 1,2,...,N
         IF CARD IS NEW
            PRINT 1 LINE WITH "*" THUS
INPUT A LIST OF VALUES ENDING IT WITH "*"
            START NEW CARD
         ALWAYS
         NOW READ.A.REAL.VECTOR  GIVEN 0, MIN.VALUES(*), MAX.VALUES(*)
            YIELDING VALUES(*)
         CHECK.FOR.ABORT
         LET N.VALUES = DIM.F(VALUES(*))
         IF N.VALUES > NMAX
            PRINT 2 LINES WITH NMAX AND N.VALUES THUS
A MAXIMUM OF **** VALUES IS PERMITTED.  YOU HAVE SPECIFIED **** VALUES.
PLEASE INPUT YOUR LIST AGAIN.
            UNTIL CARD IS NEW
               SKIP 1 FIELD
            RELEASE VALUES(*)
            CYCLE  ''TO ANOTHER ATTEMPT
         OTHERWISE
         JUMP AHEAD

      CASE(2)'  ''FORM 2  XS, DELTAX, N
         IF CARD IS NEW
            PRINT 1 LINE THUS
INPUT A STARTING VALUE
            START NEW CARD
         ALWAYS
         NOW READ.A.REAL  GIVEN -RINF.C, VMIN(IVINDEX), VMAX(IVINDEX)
            YIELDING XS
         CHECK.FOR.ABORT
         IF CARD IS NEW
            PRINT 1 LINE THUS
INPUT AN INCREMENT
            START NEW CARD
         ALWAYS
         NOW READ.A.REAL  GIVEN -RINF.C, 10.0 ** (-3.0), VMAX(IVINDEX)
            YIELDING DELTAX
         CHECK.FOR.ABORT
         IF CARD IS NEW
            PRINT 1 LINE THUS
INPUT THE NUMBER OF VALUES
            START NEW CARD
         ALWAYS
         NOW READ.AN.INTEGER  GIVEN -INF.C, 2, NMAX, 1
            YIELDING N.VALUES
         CHECK.FOR.ABORT
         RESERVE VALUES(*) AS N.VALUES
         FOR I = 1 TO N.VALUES,
            LET VALUES(I) = XS + (I - 1) * DELTAX
         JUMP AHEAD

      CASE(3)'  ''FORM 3  XS, DELTAX, XE
         IF CARD IS NEW
            PRINT 1 LINE THUS
INPUT A STARTING VALUE
            START NEW CARD
         ALWAYS
         NOW READ.A.REAL  GIVEN -RINF.C, VMIN(IVINDEX), VMAX(IVINDEX)
            YIELDING XS
         CHECK.FOR.ABORT
         IF CARD IS NEW
            PRINT 1 LINE THUS
INPUT AN INCREMENT
            START NEW CARD
         ALWAYS
         NOW READ.A.REAL  GIVEN -RINF.C, 10.0 ** (-3.0), VMAX(IVINDEX)
            YIELDING DELTAX
         IF CARD IS NEW
            PRINT 1 LINE THUS
INPUT AN ENDING VALUE
            START NEW CARD
         ALWAYS
         NOW READ.A.REAL  GIVEN -RINF.C, XS, VMAX(IVINDEX)
            YIELDING XE
         CHECK.FOR.ABORT
         LET LAMDA = ABS.F((XE - XS) / DELTAX)
         LET N.VALUES = 1 + TRUNC.F(LAMDA)
         IF N.VALUES > NMAX
            PRINT 2 LINES WITH NMAX AND N.VALUES THUS
A MAXIMUM OF **** VALUES IS PERMITTED.  YOU HAVE SPECIFIED **** VALUES.
PLEASE INPUT YOUR SPECIFICATIONS AGAIN.
            UNTIL CARD IS NEW
               SKIP 1 FIELD
            CYCLE  ''TO ANOTHER ATTEMPT
         OTHERWISE
         RESERVE VALUES(*) AS N.VALUES
         FOR I = 1 TO N.VALUES,
            LET VALUES(I) = XS + (I - 1) * DELTAX
         JUMP AHEAD

      CASE(4)'  ''FORM 4  XS, XE, N
         IF CARD IS NEW
            PRINT 1 LINE THUS
INPUT A STARTING VALUE
            START NEW CARD
         ALWAYS
         NOW READ.A.REAL  GIVEN -RINF.C, VMIN(IVINDEX), VMAX(IVINDEX)
            YIELDING XS
         CHECK.FOR.ABORT
         IF CARD IS NEW
            PRINT 1 LINE THUS
INPUT AN ENDING VALUE
            START NEW CARD
         ALWAYS
         NOW READ.A.REAL  GIVEN -RINF.C, XS, VMAX(IVINDEX)
            YIELDING XE
         CHECK.FOR.ABORT
         IF CARD IS NEW
            PRINT 1 LINE THUS
INPUT THE NUMBER OF VALUES
            START NEW CARD
         ALWAYS
         NOW READ.AN.INTEGER  GIVEN -INF.C, 2, NMAX, 1
            YIELDING N.VALUES
         CHECK.FOR.ABORT
         LET DELTAX = (XE - XS) / (N.VALUES - 1)
         RESERVE VALUES(*) AS N.VALUES
         FOR I = 1 TO N.VALUES,
            LET VALUES(I) = XS + (I - 1) * DELTAX
         JUMP AHEAD

      ENDSELECT

      ''CHECK THE LIST FOR OUT OF BOUNDS VALUES
      LET FLAG = 0
      ITERATING FOR I = 1 TO N.VALUES, DO
         IF VALUES(I) ) VMIN(IVINDEX) OR VALUES(I) > VMAX(IVINDEX)
            ADD 1 TO FLAG
         ALWAYS
      REPEAT  ''FOR NEXT I
      IF FLAG NE 0
         WRITE FLAG AS B 1,"YOUR SET OF INDEPENDENT VARIABLE VALUES WHICH IS",
            " SHOWN BELOW HAS", I 5, " ENTRIES",/, "WHICH ARE OUTSIDE THE ",
            "LIMITS FOR VARIABLE"
         NOW QUOTE.TEXT  GIVEN IVNAMES(IVINDEX)
         WRITE AS /
         NOW WRITE.A.REAL.VECTOR  GIVEN VALUES(*)
         PRINT 1 LINE THUS
DO YOU WISH TO RETAIN IT ANYWAY?
         START NEW CARD
         NOW INTERPRET.THE.NEXT.WORD.IF.NOT.ABORT  GIVEN 1
            YIELDING CHOICE
         CHECK.FOR.ABORT
         IF CHOICE = 1  ''YES
            LEAVE  ''THE LOOP
         OTHERWISE
         RELEASE VALUES(*)
         WRITE VMIN(IVINDEX), VMAX(IVINDEX) AS "YOUR ENTRIES SHOULD LIE",
            " BETWEEN", E(13,5), " AND", E(13,5), ".", /
         UNTIL CARD IS NEW
            SKIP 1 FIELD
         CYCLE  ''TO ANOTHER ATTEMPT
      OTHERWISE
      LEAVE  ''THE LOOP
   REPEAT  ''UNTIL USER ENTERS AN ACCEPTABLE SET OF VALUES

   IF CARD IS NEW
      PRINT 1 LINE THUS
DO YOU WISH TO DISPLAY THE SET OF INDEPENDENT VARIABLE VALUES?
      START NEW CARD
   ALWAYS
   NOW INTERPRET.THE.NEXT.WORD.IF.NOT.ABORT  GIVEN 1
      YIELDING CHOICE
   CHECK.FOR.ABORT
   IF CHOICE = 1  ''YES
      NOW WRITE.A.REAL.VECTOR  GIVEN VALUES(*)
   ALWAYS
   RESERVE TABLE(*,*) AS 24 BY N.VALUES
   RELEASE TABLE(1,*), MIN.VALUES(*), MAX.VALUES(*)
   STORE VALUES(*) IN TABLE(1,*)
   RETURN

   'ABORT'  ''HERE IF USER ENTERS ABORT
   RELEASE VALUES(*), MIN.VALUES(*), MAX.VALUES(*)

   RETURN
END
ROUTINE TO CALCULATE.INVESTMENT.TAX.CREDIT.RATE
   YIELDING ITC

   DEFINE ITC, TL AS REAL VARIABLES

   LET TL = TLF.P * EL.P
   IF T.P LE TL
      LET ITC = A.P
      RETURN
   OTHERWISE  ''T.P > TL
   IF M.P LE TL
      LET ITC = A.P * UF.P
      RETURN
   OTHERWISE  ''M.P > TL
   IF B.P LE TL
      LET ITC = A.P * LF.P
      RETURN
   OTHERWISE  ''B.P > TL

   RETURN  ''WITH ITC = 0.0
END
ROUTINE TO PRINT.THE.RESULTS

   DEFINE CHOICE, REPORT.OUTPUT.FILE, NPL, STATUS, NDL, VINDEX, I,
      J, K, L, NG, NL AS INTEGER VARIABLES
   DEFINE MATCH.FLAG AS AN ALPHA VARIABLE
   DEFINE DISPLAY.LIST AS A 1-DIM, INTEGER ARRAY
   DEFINE VERY.FIRST.TIME, FIRST.TIME, ROF AS INTEGER VARIABLES

   IF CARD IS NEW
      PRINT 1 LINE THUS
DO YOU WISH TO PRINT ANY SENSITIVITY STUDY RESULTS?
      START NEW CARD
   ALWAYS
   NOW INTERPRET.THE.USERS.NEXT.WORD  GIVEN 1, 0
      YIELDING CHOICE
   IF CHOICE = 2  ''NO
      RETURN
   OTHERWISE

   LET REPORT.OUTPUT.FILE = NORMAL.OUTPUT.UNIT
   LET ROF = 0
   LET NPL = 5
   IF CARD IS NEW
      PRINT 1 LINE THUS
DO YOU WISH TO HAVE THE OUTPUT DIRECTED TO YOUR TERMINAL?
      START NEW CARD
   ALWAYS
   NOW INTERPRET.THE.USERS.NEXT.WORD  GIVEN 1, 0
      YIELDING CHOICE
   IF CHOICE = 2  ''NO
      LET REPORT.OUTPUT.FILE = ALTERNATE.PRINT.FILE
      LET ROF = 1
      LET NPL = 9
   ALWAYS

   IF CARD IS NEW
      PRINT 1 LINE THUS
INPUT A REPORT TITLE
      START NEW CARD
   ALWAYS
   RELEASE REPORT.TITLE ''TO GET RID OF ANY OLD TITLE
   NOW CHECK.THE.NEXT.NONBLANK.LINE.FOR.DEFAULT
      YIELDING STATUS
   IF STATUS NE 0  ''USER WANTS DEFAULT
      STASH "SENSITIVITY STUDY REPORT" INTO REPORT.TITLE
      PRINT 1 LINE THUS
THIS TITLE HAS BEEN DEFAULTED WITH THE FOLLOWING TEXT:
      NOW QUOTE.TEXT  GIVEN REPORT.TITLE
      WRITE AS /
   ELSE
      NOW READ.A.LINE.OF.TEXT  YIELDING REPORT.TITLE
      IF ABORT.FLAG = 1 ''(ON)
         SAY "***** RUN ABORTED.",/
         STOP
      OTHERWISE
   ALWAYS

   USE REPORT.OUTPUT.FILE FOR OUTPUT
   LET PAGE.V = 0
   USE NORMAL.OUTPUT.UNIT FOR OUTPUT

   ITERATING UNTIL TERMINATED, DO

      RELEASE DISPLAY.LIST(*)
      LET NDL = 0
      USE NORMAL.OUTPUT.UNIT FOR OUTPUT
      LET LINES.V = INF.C
      STORE 0 IN HEADING.V
      IF VERY.FIRST.TIME NE 0 AND ROF = 0
         SKIP 2 LINES
      ALWAYS

      IF CARD IS NEW
         PRINT 1 LINE THUS
ENTER A DISPLAY COMMAND FOLLOWED BY THE VARIABLES TO BE DISPLAYED OR ENTER DONE
         START NEW CARD
      ALWAYS
      NOW INTERPRET.THE.USERS.NEXT.WORD  GIVEN 5, 0
         YIELDING CHOICE
      IF CHOICE = 0 ''USER ENTERED "DONE"
         RELEASE OUTPUT.LIST(*), REPORT.TITLE
         RETURN
      OTHERWISE  ''USER ENTERED DISPLAY

      IF CARD IS NEW  ''USER ENTERED DISPLAY BUT NO LIST
         RELEASE OUTPUT.LIST(*), REPORT.TITLE
         RETURN
      OTHERWISE  ''USER ENTERED A LIST

      ITERATING UNTIL TERMINATED, DO
         NOW INTERPRET.THE.USERS.NEXT.WORD  GIVEN 3, 1
         YIELDING VINDEX

         IF VINDEX ) 0  ''EMPTY REMAINING LINE SO QUIT
            LEAVE  ''THE LOOP
         OTHERWISE

         IF VINDEX = 0  ''USER ENTERED ALL IN HIS LIST
            LET NDL = 23
            RESERVE DISPLAY.LIST(*) AS 23
            FOR I = 1 TO 23,
               LET DISPLAY.LIST(I) = I
            LEAVE  ''THE LOOP
         OTHERWISE

         ''SEE IF VINDEX ALREADY IN INPUT LIST
         LET MATCH.FLAG = "NO.M"
         ITERATING FOR EACH ELEMENT IN VECTOR, DO
            IF WORD.POINTER(ELEMENT) = VINDEX
               LET MATCH.FLAG = "M"
               LEAVE  ''THE LOOP
            OTHERWISE
         REPEAT  ''FOR THE NEXT ELEMENT
         IF MATCH.FLAG = "M"
            WRITE AS B 1, "THE VARIABLE"
            NOW QUOTE.TEXT  GIVEN VNAMES(VINDEX)
            WRITE AS "HAS ALREADY APPEARED IN YOUR LIST.",/
            WRITE AS "THIS SECOND OCCURENCE IS IGNORED.",/
            CYCLE
         OTHERWISE
         CREATE AN ELEMENT
         LET WORD.POINTER(ELEMENT) = VINDEX
         FILE ELEMENT IN VECTOR
      REPEAT  ''UNTIL USER ENTERS ALL OR LINE IS EMPTY

      IF NDL = 0
         LET NDL = N.VECTOR
         IF NDL = 0  ''USER LIST HAS NO VALID ENTRIES
            CYCLE  ''TO ANOTHER ATTEMPT AT DISPLAY
         ALWAYS
         RESERVE DISPLAY.LIST(*) AS NDL
         LET I = 0
         ITERATING FOR EACH ELEMENT IN VECTOR, DO
            REMOVE THIS ELEMENT FROM VECTOR
            ADD 1 TO I
            LET DISPLAY.LIST(I) = WORD.POINTER(ELEMENT)
            DESTROY THIS ELEMENT
         REPEAT  ''FOR THE NEXT ELEMENT
      ELSE  ''NDL NE 0
         ITERATING FOR EACH ELEMENT IN VECTOR, DO
            REMOVE THIS ELEMENT FROM VECTOR
            DESTROY THIS ELEMENT
         REPEAT  ''FOR THE NEXT ELEMENT
      ALWAYS

      LET NG = DIV.F(NDL, NPL)
      LET NL = NDL - NPL*NG
      LET FIRST.TIME = 0
      USE REPORT.OUTPUT.FILE FOR OUTPUT
      LET LINES.V = 55
      STORE 'PSRH' IN HEADING.V
      ITERATING FOR J = 1 TO NG, DO
         RELEASE OUTPUT.LIST(*)
         RESERVE OUTPUT.LIST(*) AS NPL
         LET K = (J-1) * NPL
         FOR I = 1 TO NPL,
            LET OUTPUT.LIST(I) = DISPLAY.LIST(K+I)
         IF VERY.FIRST.TIME = 0 OR (FIRST.TIME = 0 AND ROF = 0)
            OR (LINES.V - LINE.V) ) 8
            START NEW PAGE
         ELSE
            SKIP 2 LINES
            NOW PRINT.COLUMN.HEADINGS
         ALWAYS
         ITERATING FOR I = 1 TO N.VALUES, DO
            WRITE AS B 3
            NOW WRITE.A.REAL.VALUE  GIVEN TABLE(1,I), 5
            ITERATING FOR L = 1 TO NPL, DO
               LET K = 1 + OUTPUT.LIST(L)
               WRITE AS S 2
               NOW WRITE.A.REAL.VALUE  GIVEN TABLE(K,I), 5
            REPEAT  ''FOR THE NEXT L
            WRITE AS /
         REPEAT  ''FOR THE NEXT I
         ADD 1 TO VERY.FIRST.TIME
         ADD 1 TO FIRST.TIME
      REPEAT  ''FOR THE NEXT J

      IF NL NE 0
         RELEASE OUTPUT.LIST(*)
         RESERVE OUTPUT.LIST(*) AS NL
         LET K = NG*NPL
         FOR I = 1 TO NL,
            LET OUTPUT.LIST(I) = DISPLAY.LIST(K+I)
         IF VERY.FIRST.TIME = 0 OR (FIRST.TIME = 0 AND ROF = 0)
            OR (LINES.V - LINE.V) ) 8
            START NEW PAGE
         ELSE
            SKIP 2 LINES
            NOW PRINT.COLUMN.HEADINGS
         ALWAYS
         ITERATING FOR I = 1 TO N.VALUES, DO
            WRITE AS B 3
            NOW WRITE.A.REAL.VALUE  GIVEN TABLE(1,I), 5
            ITERATING FOR L = 1 TO NL, DO
               LET K = 1 + OUTPUT.LIST(L)
               WRITE AS S 2
               NOW WRITE.A.REAL.VALUE  GIVEN TABLE(K,I), 5
            REPEAT  ''FOR THE NEXT L
            WRITE AS /
         REPEAT  ''FOR THE NEXT I
         ADD 1 TO VERY.FIRST.TIME
      ALWAYS

   REPEAT ''UNTIL THE USER ENTERS "DONE"

   USE NORMAL.OUTPUT.UNIT FOR OUTPUT
   RELEASE OUTPUT.LIST(*), DISPLAY.LIST(*)
   LET LINES.V = INF.C
   STORE 0 IN HEADING.V

   RETURN
END
ROUTINE TO PLOT.THE.RESULTS

   DEFINE CHOICE, PLOT.FILE, PLOT.TYPE, VINDEX, NPL, I, VINDEX1, VINDEX2,
      NCHAR, PLOT.TITLE, NCHARP, NCHARI, HORIZONTAL.AXIS.TITLE,
      CASE.IDENTIFIER.TITLE, PLOT.SUBTITLE
      AS INTEGER VARIABLES
   DEFINE MATCH.FLAG AS AN ALPHA VARIABLE
   DEFINE PLOT.LIST AS A 1-DIM, INTEGER ARRAY

   IF CARD IS NEW
      PRINT 1 LINE THUS
DO YOU WISH TO PLOT ANY SENSITIVITY STUDY RESULTS?
      START NEW CARD
   ALWAYS
   NOW INTERPRET.THE.USERS.NEXT.WORD  GIVEN 1, 0
      YIELDING CHOICE
   IF CHOICE = 2  ''NO
      RETURN
   OTHERWISE

   ''DETERMINE NUMBER OF CHARACTERS TO PRINT IN PROCESS.PRODUCT.UNITS
   NOW DETERMINE.CHARACTER.COUNT  GIVEN PROCESS.PRODUCT.UNITS
      YIELDING NCHARP
   LET NCHARP = MIN.F(NCHARP, 11)

   ''DETERMINE NUMBER OF CHARACTERS TO PRINT IN INDUSTRY.PRODUCTION.UNITS
   NOW DETERMINE.CHARACTER.COUNT  GIVEN INDUSTRY.PRODUCTION.UNITS
      YIELDING NCHARI
   LET NCHARI = MIN.F(NCHARI, 11)

   ''GENERATE CASE.IDENTIFIER.TITLE
   LET XXX.UNIT = WRITE.V
   USE THE BUFFER FOR OUTPUT
   WRITE SIZE AS /, B 1, "SIZE.INDEX: ", I 2, S 2, "COMPANY: "
   NOW PRINT.TEXT  GIVEN COMPANY.REFERENT
   IF PROCESS.FLAG NE 0
      WRITE AS S 2, "PROCESS: "
      NOW PRINT.TEXT  GIVEN PROCESS.REFERENT
   ALWAYS
   NOW LOAD.SOME.TEXT  YIELDING CASE.IDENTIFIER.TITLE

   LET PLOT.FILE = NORMAL.OUTPUT.UNIT
   IF CARD IS NEW
      PRINT 1 LINE THUS
DO YOU WISH TO HAVE THE PLOTS DIRECTED TO YOUR TERMINAL?
      START NEW CARD
   ALWAYS
   NOW INTERPRET.THE.USERS.NEXT.WORD  GIVEN 1, 0
      YIELDING CHOICE
   IF CHOICE = 2  ''NO
      LET PLOT.FILE = ALTERNATE.PRINT.FILE
   ALWAYS

   ITERATING UNTIL TERMINATED, DO
      LET NPL = 0
      RELEASE PLOT.LIST(*), PLOT.TITLE, PLOT.SUBTITLE

      IF CARD IS NEW
         PRINT 1 LINE THUS
ENTER A PLOT COMMAND FOLLOWED BY THE VARIABLES TO BE PLOTTED OR ENTER DONE
         START NEW CARD
      ALWAYS
      NOW INTERPRET.THE.USERS.NEXT.WORD  GIVEN 6, 0
         YIELDING CHOICE
      IF CHOICE = 0  ''USER ENTERED DONE
         RELEASE CASE.IDENTIFIER.TITLE
         RETURN
      OTHERWISE  ''USER ENTERED PLOT

      IF CARD IS NEW  ''USER ENTERED PLOT WITH NO LIST SO QUIT
         RELEASE CASE.IDENTIFIER.TITLE
         RETURN
      ALWAYS

      LET ABORT.FLAG = 0
      LET PLOT.TYPE = 0
      ITERATING UNTIL TERMINATED, DO
         NOW INTERPRET.THE.USERS.NEXT.WORD  GIVEN 7, 1
            YIELDING VINDEX

         IF VINDEX ) 0  ''EMPTY REMAINING LINE
            IF PLOT.TYPE = 0
               LEAVE  ''THE LOOP
            OTHERWISE  ''USER ENTERED "PLOT V1 VERSUS"
            'ERROR'
            PRINT 1 LINE THUS
YOUR PLOT COMMAND IS INVALID SO THIS LINE IS IGNORED
            UNTIL CARD IS NEW,
               SKIP 1 FIELD
            ITERATING FOR EACH ELEMENT IN VECTOR, DO
               REMOVE THIS ELEMENT FROM VECTOR
               DESTROY THIS ELEMENT
            REPEAT  ''FOR THE NEXT ELEMENT
            LET ABORT.FLAG = 1
            LEAVE  ''THE LOOP
         OTHERWISE

         IF VINDEX = 0  ''USER ENTERED "ALL" IN HIS LIST
            IF PLOT.TYPE NE 0  ''USER ENTERED "PLOT V1 VERSUS ALL"
               GO TO ERROR
            OTHERWISE
            RESERVE PLOT.LIST(*) AS 23
            LET NPL = 23
            FOR I = 1 TO 23,
               LET PLOT.LIST(I) = I
            LEAVE  ''THE LOOP
         OTHERWISE

         IF VINDEX = 24  ''USER ENTERED "VERSUS"
            IF N.VECTOR NE 1
               GO TO ERROR
            OTHERWISE
            LET ELEMENT = F.VECTOR
            REMOVE THIS ELEMENT FROM VECTOR
            LET VINDEX1 = WORD.POINTER(ELEMENT)
            DESTROY THIS ELEMENT
            LET PLOT.TYPE = 1
            CYCLE  ''TO THE NEXT LIST ENTRY
         OTHERWISE

         IF PLOT.TYPE = 1  ''USER ENTERED "PLOT V1 VERSUS V2"
            LET VINDEX2 = VINDEX
            IF VINDEX2 = VINDEX1
               GO TO ERROR
            OTHERWISE
            UNTIL CARD IS NEW,
               SKIP 1 FIELD
            LEAVE  ''THE LOOP
         OTHERWISE

         ''SEE IF VINDEX ALREADY IN INPUT LIST
         LET MATCH.FLAG = "NO.M"
         ITERATING FOR EACH ELEMENT IN VECTOR, DO
            IF WORD.POINTER(ELEMENT) = VINDEX
               LET MATCH.FLAG = "M"
               LEAVE  ''THE LOOP
            OTHERWISE
         REPEAT  ''FOR THE NEXT ELEMENT
         IF MATCH.FLAG = "M"
            WRITE AS B 1, "THE VARIABLE"
            NOW QUOTE.TEXT  GIVEN VNAMES(VINDEX)
            WRITE AS "HAS ALREADY APPEARED IN YOUR LIST.",/
            WRITE AS "THIS SECOND OCCURENCE IS IGNORED.",/
            CYCLE  ''TO NEXT ENTRY IN LIST
         OTHERWISE
         CREATE AN ELEMENT
         LET WORD.POINTER(ELEMENT) = VINDEX
         FILE ELEMENT IN VECTOR
      REPEAT  ''UNTIL USER ENTERS "ALL" OR LINE IS EMPTY

      IF ABORT.FLAG = 1
         CYCLE  ''TO ANOTHER PLOT COMMAND
      OTHERWISE

      IF PLOT.TYPE NE 0  ''USER ENTERED "PLOT V1 VERSUS V2"

         ''GENERATE PLOT.TITLE
         LET XXX.UNIT = WRITE.V
         USE THE BUFFER FOR OUTPUT
         WRITE AS B 1
         NOW PRINT.TEXT  GIVEN VNAMES(VINDEX1)
         IF VINDEX1 > 5
            WRITE REPORT.YEAR AS S 1, "$(", I 4, ")"
         ALWAYS
         IF VINDEX1 = 6 OR VINDEX1 = 7
            WRITE AS "/"
            IF VINDEX1 = 6
               NOW PRINT.CHARACTERS  GIVEN PROCESS.PRODUCT.UNITS, NCHARP
            ELSE  ''VINDEX1 = 7
               NOW PRINT.CHARACTERS  GIVEN INDUSTRY.PRODUCTION.UNITS, NCHARI
            ALWAYS
            NOW MAKE.THE.UNITS.SINGULAR
         ALWAYS
         WRITE AS S 1, "VERSUS "
         NOW PRINT.TEXT  GIVEN VNAMES(VINDEX2)
         IF VINDEX2 > 5
            WRITE REPORT.YEAR AS S 1, "$(", I 4, ")"
         ALWAYS
         IF VINDEX2 = 6 OR VINDEX2 = 7
            WRITE AS "/"
            IF VINDEX2 = 6
               NOW PRINT.CHARACTERS  GIVEN PROCESS.PRODUCT.UNITS, NCHARP
            ELSE  ''VINDEX2 = 7
               NOW PRINT.CHARACTERS GIVEN INDUSTRY.PRODUCTION.UNITS, NCHARI
            ALWAYS
            NOW MAKE.THE.UNITS.SINGULAR
         ALWAYS
         NOW LOAD.SOME.TEXT  YIELDING PLOT.TITLE

         ''GENERATE PLOT.SUBTITLE
         LET XXX.UNIT = WRITE.V
         USE THE BUFFER FOR OUTPUT
         WRITE AS /, "PARAMETRIC PLOT PARAMETER IS "
         NOW PRINT.TEXT  GIVEN IVNAMES(IVINDEX)
         NOW LOAD.SOME.TEXT  YIELDING PLOT.SUBTITLE

         NOW PLOT.A.CURVE.ON.THE.PRINTER
            GIVEN PLOT.FILE, CASE.IDENTIFIER.TITLE, PLOT.TITLE, PLOT.SUBTITLE,
               VNAMES(VINDEX1), VNAMES(VINDEX2),
               TABLE(1+VINDEX2,*), TABLE(1+VINDEX1,*)
         CYCLE  ''TO THE NEXT PLOT COMMAND
      OTHERWISE  ''PLOT.TYPE = 0

      IF NPL = 0
         LET NPL = N.VECTOR
         IF NPL = 0  ''USER LIST HAS NO VALID ENTRIES
            CYCLE  ''TO ANOTHER ATTEMPT AT PLOT
         ALWAYS
         RESERVE PLOT.LIST(*) AS NPL
         LET I = 0
         ITERATING FOR EACH ELEMENT IN VECTOR, DO
            REMOVE THIS ELEMENT FROM VECTOR
            ADD 1 TO I
            LET PLOT.LIST(I) = WORD.POINTER(ELEMENT)
            DESTROY THIS ELEMENT
         REPEAT  ''FOR NEXT ELEMENT
      ELSE  ''NPL NE 0
         ITERATING FOR EACH ELEMENT IN VECTOR, DO
            REMOVE THIS ELEMENT FROM VECTOR
            DESTROY THIS ELEMENT
         REPEAT  ''FOR THE NEXT ELEMENT
      ALWAYS

      ITERATING FOR I = 1 TO NPL, DO

         ''GENERATE PLOT TITLE
         LET XXX.UNIT = WRITE.V
         USE THE BUFFER FOR OUTPUT
         WRITE AS B 1
         NOW PRINT.TEXT  GIVEN VNAMES(PLOT.LIST(I))
         IF PLOT.LIST(I) > 5
            WRITE REPORT.YEAR AS S 1, "$(", I 4, ")"
         ALWAYS
         IF PLOT.LIST(I) = 6 OR PLOT.LIST(I) = 7
            WRITE AS "/"
            IF PLOT.LIST(I) = 6
               NOW PRINT.CHARACTERS  GIVEN PROCESS.PRODUCT.UNITS, NCHARP
            ELSE  ''PLOT.LIST(I) = 7
               NOW PRINT.CHARACTERS  GIVEN INDUSTRY.PRODUCTION.UNITS, NCHARI
            ALWAYS
            NOW MAKE.THE.UNITS.SINGULAR
         ALWAYS
         WRITE AS S 1, "VERSUS "
         NOW PRINT.TEXT  GIVEN IVNAMES(IVINDEX)
         NOW LOAD.SOME.TEXT  YIELDING PLOT.TITLE

         ''GENERATE HORIZONTAL AXIS TITLE
         LET XXX.UNIT = WRITE.V
         USE THE BUFFER FOR OUTPUT
         WRITE AS /, B 1
         NOW PRINT.TEXT  GIVEN IVNAMES(IVINDEX)
         WRITE AS S 1, "("
         NOW PRINT.TEXT  GIVEN IVUNITS(IVINDEX)
         WRITE AS ")"
         NOW LOAD.SOME.TEXT  YIELDING HORIZONTAL.AXIS.TITLE

         NOW PLOT.A.CURVE.ON.THE.PRINTER
            GIVEN PLOT.FILE, CASE.IDENTIFIER.TITLE, PLOT.TITLE, 0,
               VNAMES(PLOT.LIST(I)), HORIZONTAL.AXIS.TITLE,
               TABLE(1,*), TABLE(1+PLOT.LIST(I),*)
         RELEASE PLOT.TITLE, HORIZONTAL.AXIS.TITLE
      REPEAT  ''FOR THE NEXT I

   REPEAT  ''UNTIL THE USER ENTERS "DONE"

   RETURN
END
ROUTINE TO PRINT.SENSITIVITY.REPORT.HEADING

   DEFINE END, NCHAR, SUBTITLE AS INTEGER VARIABLES

   LET END = 79
   IF WRITE.V = ALTERNATE.PRINT.FILE
      LET END = 132
   ALWAYS

   ''PRINT MAIN TITLE LINE
   WRITE AS B END - 27
   NOW PRINT.TEXT  GIVEN TIME.OF.DAY(*)
   WRITE AS S 2
   NOW PRINT.TEXT  GIVEN CURRENT.DATE(*)
   WRITE PAGE.V AS S 2, "PAGE", I 4
   NOW DETERMINE.CHARACTER.COUNT  GIVEN REPORT.TITLE  YIELDING NCHAR
   LET NCHAR = MIN.F(NCHAR, END - 29)
   WRITE AS B 1
   NOW PRINT.CHARACTERS  GIVEN REPORT.TITLE, NCHAR
   WRITE AS /

   ''PRINT SUBTITLE LINE
   LET XXX.UNIT = WRITE.V
   USE THE BUFFER FOR OUTPUT
   WRITE SIZE AS /, B 1, "SIZE.INDEX: ", I 2, S 2, "COMPANY: "
   NOW PRINT.TEXT  GIVEN COMPANY.REFERENT
   IF PROCESS.FLAG NE 0
      WRITE AS S 2, "PROCESS: "
      NOW PRINT.TEXT  GIVEN PROCESS.REFERENT
   ALWAYS
   NOW LOAD.SOME.TEXT  YIELDING SUBTITLE
   NOW DETERMINE.CHARACTER.COUNT  GIVEN SUBTITLE  YIELDING NCHAR
   WRITE AS B END - NCHAR + 1
   NOW PRINT.CHARACTERS  GIVEN SUBTITLE, NCHAR
   WRITE AS /
   RELEASE SUBTITLE

   SKIP 1 LINE
   NOW PRINT.COLUMN.HEADINGS

   RETURN
END
ROUTINE TO PRINT.COLUMN.HEADINGS

   DEFINE NCHAR, L, N, J, P, I, FLAG1 AS INTEGER VARIABLES

   NOW DETERMINE.CHARACTER.COUNT  GIVEN IVNAMES(IVINDEX)
      YIELDING NCHAR
   LET L = 8 - DIV.F(NCHAR-1, 2)
   WRITE AS B L
   NOW PRINT.TEXT  GIVEN IVNAMES(IVINDEX)

   LET N = DIM.F(OUTPUT.LIST(*))
   ITERATING FOR J = 1 TO N, DO
      LET P = 8 + 13 * J
      LET I = OUTPUT.LIST(J)
      IF (I = 6 OR I = 7) AND PROCESS.FLAG NE 0  ''PRINT VALUE ADDED NOT PRICE
         WRITE AS B P-5, "VALUE ADDED"
      ELSE
         NOW DETERMINE.CHARACTER.COUNT  GIVEN VNAMES(I)  YIELDING NCHAR
         LET L = P - DIV.F(NCHAR-1, 2)
         WRITE AS B L
         NOW PRINT.TEXT  GIVEN VNAMES(I)
      ALWAYS
   REPEAT  ''FOR NEXT J
   WRITE AS /

   NOW DETERMINE.CHARACTER.COUNT  GIVEN IVUNITS(IVINDEX)
      YIELDING NCHAR
   LET L = 8 - DIV.F(NCHAR-1, 2)
   WRITE AS B L
   NOW PRINT.TEXT  GIVEN IVUNITS(IVINDEX)

   ITERATING FOR J = 1 TO N, DO
      LET P = 8 + 13 * J
      LET I = OUTPUT.LIST(J)
      IF I = 2  OR  I > 5  ''PRINT UNITS
         WRITE REPORT.YEAR AS B P-3, "$(", I 4, ")"
         IF I = 2  OR  I ) 8
            WRITE AS "/"
            LET FLAG1 = 1
         ALWAYS
      ALWAYS
   REPEAT  ''FOR NEXT J
   WRITE AS /  ''DUMP UNITS LINE

   IF FLAG1 = 0  ''NO PRICES
      RETURN
   OTHERWISE

   ITERATING FOR J = 1 TO N, DO
      LET P = 8 + 13 * J
      LET I = OUTPUT.LIST(J)
      IF I = 2
         WRITE AS B P-1, "SQFT"
         CYCLE  ''TO THE NEXT J
      OTHERWISE
      IF I = 6  ''PRINT PROCESS.PRODUCT.UNITS
         NOW DETERMINE.CHARACTER.COUNT  GIVEN PROCESS.PRODUCT.UNITS
            YIELDING NCHAR
         LET NCHAR = MIN.F(NCHAR, 11)
         LET L = P - DIV.F(NCHAR-1, 2)
         WRITE AS B L
         NOW PRINT.CHARACTERS  GIVEN PROCESS.PRODUCT.UNITS, NCHAR
         NOW MAKE.THE.UNITS.SINGULAR
         CYCLE  ''TO THE NEXT J
      OTHERWISE
      IF I = 7  ''PRINT INDUSTRY.PRODUCTION.UNITS
         NOW DETERMINE.CHARACTER.COUNT  GIVEN INDUSTRY.PRODUCTION.UNITS
            YIELDING NCHAR
         LET NCHAR = MIN.F(NCHAR, 11)
         LET L = P - DIV.F(NCHAR-1, 2)
         WRITE AS B L
         NOW PRINT.CHARACTERS  GIVEN INDUSTRY.PRODUCTION.UNITS, NCHAR
         NOW MAKE.THE.UNITS.SINGULAR
      ALWAYS
   REPEAT  ''FOR THE NEXT J
   WRITE AS /

   RETURN
END
ROUTINE TO DISPLAY.THE.TRANSFORMATION.MATRIX

   DEFINE I, J AS INTEGER VARIABLES

   SKIP 2 LINES
   WRITE AS B 31, "TRANSFORMATION MATRIX", /
   SKIP 1 LINE
   WRITE AS B 9
   FOR I = 1 TO 5,
      WRITE I AS S 12, I 1
   WRITE AS /

   WRITE AS B 3, "C", B 14
   ITERATING FOR J = 1 TO 5, DO
      WRITE AS S 2
      NOW WRITE.A.REAL.VALUE  GIVEN T.MATRIX(1,J), 5
   REPEAT  ''FOR NEXT J
   WRITE AS /

   ITERATING FOR I = 2 TO 17, DO
      WRITE AS B 3
      NOW PRINT.TEXT  GIVEN VNAMES(I+6)
      WRITE AS B 14
      ITERATING FOR J = 1 TO 5, DO
         WRITE AS S 2
         NOW WRITE.A.REAL.VALUE  GIVEN T.MATRIX(I,J), 5
      REPEAT  ''FOR NEXT J
      WRITE AS /
   REPEAT  ''FOR NEXT I

   RETURN
END
ROUTINE TO PLOT.A.CURVE.ON.THE.PRINTER
   GIVEN PLOT.FILE, MAIN.TITLE, PLOT.TITLE, PLOT.SUBTITLE,
      VERTICAL.AXIS.TITLE, HORIZONTAL.AXIS.TITLE, XLIST, YLIST

   DEFINE PLOT.TITLE, VERTICAL.AXIS.TITLE, HORIZONTAL.AXIS.TITLE, N, I,
      CMAX, LMAX, ML, MR, MT, MB, NCMAX, NLMAX, KX, KY, NC, NL, NM, CM,
      CSTAR, LSTAR, NV, LV, DELTATY, DELTATX, LINE, NH, CH, DUMMY,
      PLOT.FILE, MAIN.TITLE, PLOT.SUBTITLE, NS, CS, NTOTAL
      AS INTEGER VARIABLES

   DEFINE XMIN, XMAX, YMIN, YMAX, XMINBAR, XMAXBAR, YMINBAR, YMAXBAR, MX,
      MY, CPRIME, LPRIME, DELTAY, DELTAX AS REAL VARIABLES

   DEFINE XLIST, YLIST AS 1-DIM, REAL ARRAYS

   ''GET MAX AND MIN OF THE DATA POINTS
   LET N = DIM.F(XLIST(*))
   FOR I = 1 TO N,
      COMPUTE XMIN = MINIMUM AND XMAX = MAXIMUM OF XLIST(I)
   FOR I = 1 TO N,
      COMPUTE YMIN = MINIMUM AND YMAX = MAXIMUM OF YLIST(I)

   ''GET MAX, MIN AND PARTITIONING PARAMETER FOR PLOTTING
   NOW SCALE.SOME.DATA  GIVEN XMIN, XMAX
      YIELDING XMINBAR, XMAXBAR, KX, DUMMY
   NOW SCALE.SOME.DATA  GIVEN YMIN, YMAX
      YIELDING YMINBAR, YMAXBAR, KY, DUMMY

   ''LET CMAX DENOTE THE MAXIMUM NUMBER OF PRINT POSITIONS ON A PRINTED LINE
   ''AND LET LMAX DENOTE THE MAXIMUM NUMBER OF LINES ON A PRINTED PAGE.  IF
   ''NC DENOTES THE X-AXIS LENGTH, ML THE LEFT-MARGIN WIDTH, AND MR THE RIGHT-
   ''MARGIN WIDTH, THEN NC LE (CMAX-ML-MR-1).  SIMILARLY IF NL DENOTES THE
   ''Y-AXIS LENGTH, MT THE TOP-MARGIN WIDTH, AND MB THE BOTTOM MARGIN WIDTH,
   ''THEN NL LE (LMAX-MT-MB-1).
   ''LET CMAX = 132, ML = 15, MR = 4    CMAX = 79, ML = 15, MR = 4
   ''LET LMAX = 63, MT = 3, MB = 4
   ''THEN:  NC LE 112 AND NL LE 55          NC LE 59
   LET CMAX = 132
   IF PLOT.FILE = NORMAL.OUTPUT.UNIT
      LET CMAX = 79
   ALWAYS
   LET LMAX = 63
   LET ML = 15
   LET MR = 4
   LET MT = 3
   LET MB = 4
   LET NCMAX = CMAX - ML - MR - 1
   LET NLMAX = LMAX - MT - MB - 1

   ''COMPUTE THE X-AXIS LENGTH SO THAT IT IS DIVISIBLE BY KX
   LET NC = KX * DIV.F(NCMAX, KX)

   ''COMPUTE THE Y-AXIS LENGTH SO THAT IT IS DIVISIBLE BY KY
   LET NL = KY * DIV.F(NLMAX, KY)

   ''COMPUTE THE DATA TO PRINTER COORDINATE TRANSFORMATION PARAMETERS
   LET MX = NC / (XMAXBAR - XMINBAR)
   LET MY = NL / (YMAXBAR - YMINBAR)

   ''TRANSFORM THE RAW DATA TO PAGE COORDINATES
   ITERATING FOR I = 1 TO N, DO
      LET CPRIME = MX * (XLIST(I) - XMINBAR)
      LET LPRIME = MY * (YLIST(I) - YMINBAR)
      LET CSTAR = TRUNC.F(CPRIME)
      LET LSTAR = TRUNC.F(LPRIME)
      IF FRAC.F(CPRIME) > .5
         ADD 1 TO CSTAR
      ALWAYS
      IF FRAC.F(LPRIME) > .5
         ADD 1 TO LSTAR
      ALWAYS
      CREATE A POINT
      LET LINE.NUMBER(POINT) = NL - LSTAR
      LET CHARACTER.NUMBER(POINT) = CSTAR + ML + 1
      LET PLOT.SYMBOL(POINT) = "X"
      FILE POINT IN POINTS
   REPEAT  ''FOR THE NEXT I

   ''CONVERT VERTICAL AXIS TITLE INTO ENTRIES IN THE POINTS SET
   NOW DETERMINE.CHARACTER.COUNT  GIVEN VERTICAL.AXIS.TITLE  YIELDING NV
   LET LV = DIV.F(NL+1-NV, 2)
   USE THE BUFFER FOR OUTPUT
   WRITE AS /, B 1
   NOW PRINT.TEXT  GIVEN VERTICAL.AXIS.TITLE
   ITERATING FOR I = 1 TO NV, DO
      CREATE A POINT
      LET LINE.NUMBER(POINT) = LV + I - 1
      LET CHARACTER.NUMBER(POINT) = 2
      LET PLOT.SYMBOL(POINT) = OUT.F(I)
      FILE POINT IN POINTS
   REPEAT  ''FOR THE NEXT I
   WRITE AS /
   USE NORMAL.OUTPUT.UNIT FOR OUTPUT

   ''GENERATE VERTICAL AXIS TICK.MARKS SET
   LET DELTAY = (YMAXBAR - YMINBAR) / KY
   LET DELTATY = NL / KY
   ITERATING FOR I = 1 TO (KY+1), DO
      CREATE A TICK.MARK
      LET TYPE(TICK.MARK) = 0
      LET VALUE.FLAG(TICK.MARK) = 1     ''PRINT A VALUE
      LET LINE.NUMBER(TICK.MARK) = NL - (I - 1) * DELTATY
      LET CHARACTER.NUMBER(TICK.MARK) = 15
      LET PLOT.SYMBOL(TICK.MARK) = "*"
      LET VALUE(TICK.MARK) = YMINBAR + (I - 1) * DELTAY
      FILE TICK.MARK IN TICK.MARKS
   REPEAT  ''FOR THE NEXT I

   ''GENERATE HORIZONTAL AXIS TICK.MARKS SET
   LET DELTAX = (XMAXBAR - XMINBAR) / KX
   LET DELTATX = NC / KX
   ITERATING FOR I = 1 TO (KX + 1), DO
      CREATE A TICK.MARK
      LET TYPE(TICK.MARK) = 1
      LET VALUE.FLAG(TICK.MARK) = 1     ''PRINT A VALUE
      ''TO PREVENT VALUES FROM OVERSTORING ONE ANOTHER
      IF PLOT.FILE = NORMAL.OUTPUT.UNIT AND KX > 5
         IF MOD.F(KX, 2) = 0  ''KX = 6, 8, OR 10
            IF MOD.F(I, 2) = 0  ''I IS EVEN
               LET VALUE.FLAG(TICK.MARK) = 0
            ALWAYS
         ELSE  ''KX = 7 OR 9
            IF KX = 7
               IF I = 2 OR I = 4 OR I = 6 OR I = 7
                  LET VALUE.FLAG(TICK.MARK) = 0
               ALWAYS
            ELSE  ''KX = 9
               IF MOD.F(I, 3) NE 1
                  LET VALUE.FLAG(TICK.MARK) = 0
               ALWAYS
            ALWAYS
         ALWAYS
      ALWAYS
      LET CHARACTER.NUMBER(TICK.MARK) = ML + 1 + (I - 1) * DELTATX
      LET LINE.NUMBER(TICK.MARK) = NL + 1
      LET PLOT.SYMBOL(TICK.MARK) = "*"
      LET VALUE(TICK.MARK) = XMINBAR + (I - 1) * DELTAX
      FILE TICK.MARK IN TICK.MARKS
   REPEAT  ''FOR THE NEXT I

   ''PERFORM THE PLOT
   USE PLOT.FILE FOR OUTPUT
   LET LINES.V = INF.C
   START NEW PAGE

   ''COMPUTE THE TOTAL NUMBER OF LINES EXPECTED
   LET NTOTAL = NL + 1 + MB
   IF MAIN.TITLE NE 0
      ADD 1 TO NTOTAL
   ALWAYS
   IF PLOT.TITLE NE 0
      ADD 1 TO NTOTAL
   ALWAYS
   IF PLOT.SUBTITLE NE 0
      ADD 1 TO NTOTAL
   ALWAYS

   ''PRINT MAIN.TITLE (RIGHT ADJUSTED ON THE "PAGE") IF THERE IS ONE
   IF MAIN.TITLE NE 0
      NOW DETERMINE.CHARACTER.COUNT  GIVEN MAIN.TITLE  YIELDING NS
      WRITE AS B CMAX+1-NS
      NOW PRINT.CHARACTERS  GIVEN MAIN.TITLE, NS
      WRITE AS /
      ''ATTEMPT TO LEAVE A BLANK LINE
      IF PLOT.FILE = NORMAL.OUTPUT.UNIT OR NTOTAL ) LMAX
         SKIP 1 LINE
         ADD 1 TO NTOTAL
      ALWAYS
   ALWAYS

   ''PRINT PLOT.TITLE (CENTERED) IF THERE IS ONE
   IF PLOT.TITLE NE 0
      NOW DETERMINE.CHARACTER.COUNT  GIVEN PLOT.TITLE  YIELDING NM
      LET CM = ML + 1 + DIV.F(NC+1-NM, 2)
      WRITE AS B CM
      NOW PRINT.TEXT  GIVEN PLOT.TITLE
      WRITE AS /
   ALWAYS

   ''PRINT PLOT.SUBTITLE (CENTERED) IF THERE IS ONE
   IF PLOT.SUBTITLE NE 0
      NOW DETERMINE.CHARACTER.COUNT  GIVEN PLOT.SUBTITLE  YIELDING NS
      LET CS = ML + 1 + DIV.F(NC+1-NS, 2)
      WRITE AS B CS
      NOW PRINT.TEXT  GIVEN PLOT.SUBTITLE
      WRITE AS /
   ALWAYS

   ''LEAVE A BLANK LINE IF THERE IS A TITLE AND/OR SUBTITLE AND ROOM FOR IT
   IF (PLOT.TITLE NE 0 OR PLOT.SUBTITLE NE 0) AND
      (PLOT.FILE = NORMAL.OUTPUT.UNIT OR NTOTAL ) LMAX)
      SKIP 1 LINE
      ADD 1 TO NTOTAL
   ALWAYS

   ITERATING FOR LINE = 0 TO NL, DO
      WRITE AS B ML+1, "*"

      IF LINE = NL  ''PLOT THE X-AXIS
         FOR I = 0 TO NC,
            WRITE AS B I+ML+1, "*"
      ALWAYS

      ''CHECK THIS LINE FOR A TICK.MARK AND VALUE
      LET TICK.MARK = F.TICK.MARKS
      IF LINE = LINE.NUMBER(TICK.MARK)
         REMOVE THIS TICK.MARK FROM TICK.MARKS
         IF VALUE.FLAG(TICK.MARK) = 1
            NOW LABEL.A.TICK.MARK  GIVEN VALUE(TICK.MARK),
               CHARACTER.NUMBER(TICK.MARK), 2
         ALWAYS
         WRITE PLOT.SYMBOL(TICK.MARK) AS B CHARACTER.NUMBER(TICK.MARK), A 1
         DESTROY THIS TICK.MARK
      ALWAYS

      ''CHECK FOR POINTS ON THIS LINE
      ITERATING FOR EACH POINT IN POINTS, DO
         IF LINE NE LINE.NUMBER(POINT)
            LEAVE ''THE LOOP
         OTHERWISE
         REMOVE THIS POINT FROM POINTS
         WRITE PLOT.SYMBOL(POINT) AS B CHARACTER.NUMBER(POINT), A 1
         DESTROY THIS POINT
      REPEAT  ''FOR THE NEXT POINT

      WRITE AS /
   REPEAT  ''FOR THE NEXT LINE

   ''CHECK FOR TICK MARKS AND VALUES
   FOR EACH TICK.MARK IN TICK.MARKS,
      WRITE PLOT.SYMBOL(TICK.MARK) AS B CHARACTER.NUMBER(TICK.MARK), A 1
   WRITE AS /
   ITERATING FOR EACH TICK.MARK IN TICK.MARKS, DO
      REMOVE THIS TICK.MARK FROM TICK.MARKS
      IF VALUE.FLAG(TICK.MARK) = 1
         NOW LABEL.A.TICK.MARK  GIVEN VALUE(TICK.MARK),
            CHARACTER.NUMBER(TICK.MARK), 1
      ALWAYS
      DESTROY THIS TICK.MARK
   REPEAT  ''FOR NEXT TICK.MARK
   WRITE AS /

   SKIP 1 LINE

   ''INSERT THE HORIZONTAL AXIS TITLE
   NOW DETERMINE.CHARACTER.COUNT  GIVEN HORIZONTAL.AXIS.TITLE  YIELDING NH
   LET CH = ML + 1 + DIV.F(NC+1-NH, 2)
   WRITE AS B CH
   NOW PRINT.TEXT  GIVEN HORIZONTAL.AXIS.TITLE
   WRITE AS /

   IF PLOT.FILE = NORMAL.OUTPUT.UNIT
      SKIP 2 LINES
   ALWAYS

   USE NORMAL.OUTPUT.UNIT FOR OUTPUT
   RETURN
END
ROUTINE TO SCALE.SOME.DATA  GIVEN A, B  YIELDING C, D, KMAJOR, KMINOR

   DEFINE PASS, IMAX AS SAVED, INTEGER VARIABLES
   DEFINE LN10, EPSLON AS SAVED, REAL VARIABLES
   DEFINE SPAN, EKMN AS SAVED, 1-DIM, REAL ARRAYS

   DEFINE A, B, C, D, A1, B1, A2, B2, SMALL, BMA, V, G, F, X, P, UNIT,
      C1, D1 AS REAL VARIABLES
   DEFINE KMAJOR, KMINOR, I, K, OK AS INTEGER VARIABLES

   ADD 1 TO PASS
   IF PASS = 1  ''FIRST ENTRY
      LET LN10 = 2.302585093
      LET IMAX = 18
      RESERVE SPAN(*) AS 18
      RESERVE EKMN(*) AS 18
      LET SPAN(1)  = 12.0
      LET SPAN(2)  = 14.0
      LET SPAN(3)  = 15.0
      LET SPAN(4)  = 16.0
      LET SPAN(5)  = 18.0
      LET SPAN(6)  = 20.0
      LET SPAN(7)  = 20.0
      LET SPAN(8)  = 25.0
      LET SPAN(9)  = 30.0
      LET SPAN(10) = 35.0
      LET SPAN(11) = 40.0
      LET SPAN(12) = 45.0
      LET SPAN(13) = 50.0
      LET SPAN(14) = 60.0
      LET SPAN(15) = 70.0
      LET SPAN(16) = 80.0
      LET SPAN(17) = 90.0
      LET SPAN(18) = 100.0
      LET EKMN(1)  = 2.0
      LET EKMN(2)  = 2.0
      LET EKMN(3)  = 5.0
      LET EKMN(4)  = 2.0
      LET EKMN(5)  = 2.0
      LET EKMN(6)  = 2.0
      LET EKMN(7)  = 5.0
      LET EKMN(8)  = 5.0
      LET EKMN(9) =  5.0
      LET EKMN(10) = 5.0
      LET EKMN(11) = 5.0
      LET EKMN(12) = 5.0
      LET EKMN(13) = 5.0
      LET EKMN(14) = 10.0
      LET EKMN(15) = 10.0
      LET EKMN(16) = 10.0
      LET EKMN(17) = 10.0
      LET EKMN(18) = 10.0
      LET EPSLON = .0001
   ALWAYS
   LET A1 = A
   LET B1 = B
   IF B1 LE A1
      IF A1 = B1
         IF A1 NE 0.0
            LET SMALL = .01 * ABS.F(A1)
            LET A1 = A1 - SMALL
            LET B1 = B1 + SMALL
         ELSE  ''A1 = 0.0
            LET A1 = -1.0
            LET B1 = 1.0
         ALWAYS
      ELSE  ''B1 ) A1
         LET B2 = A1
         LET A1 = B1
         LET B1 = B2
      ALWAYS
   ALWAYS

   LET A2 = A1
   LET B2 = B1
   LET SMALL = (B1 - A1) * EPSLON
   IF A1 NE 0.0
      LET A1 = A1 + SMALL
   ALWAYS
   IF B1 NE 0.0
      LET B1 = B1 - SMALL
   ALWAYS
   LET BMA = B1 - A1
   IF BMA LE 0.0
      LET A1 = A2
      LET B1 = B2
      LET BMA = B1 - A1
   ALWAYS

   LET V = LOG.10.F(BMA)
   LET G = TRUNC.F(V)
   LET F = V - G
   IF F LE 0.0
      ADD 1.0 TO F
   ALWAYS
   LET X = EXP.F((F + 1.0) * LN10)
   LET P = BMA / X
   IF X LE 10.0
      LET X = X * 10.0
      LET P = P / 10.0
   ALWAYS

   FOR I = 1 TO IMAX, DO
      IF X LE SPAN(I)
         LEAVE  ''THE LOOP
      OTHERWISE
   REPEAT  ''FOR THE NEXT I
   IF I > IMAX
      LET I = IMAX
   ALWAYS

   FOR K = 1 TO 3, DO
      'OVER'   LET UNIT = EKMN(I) * P
      LET C1 = UNIT * TRUNC.F(A1 / UNIT)
      IF C1 > A1
         LET C1 = C1 - UNIT
      ALWAYS
      LET D1 = C1 + SPAN(I) * P
      IF B1 LE D1
         LET OK = 1
         LEAVE  ''THE LOOP
      OTHERWISE
      ADD 1 TO I
      IF I LE IMAX
         GO TO OVER
      OTHERWISE
      LET I = 1
      LET P = P * 10.0
   REPEAT  ''FOR THE NEXT K

   IF OK = 0
      PRINT 1 LINE THUS
SCALING ERROR IN SCALE.SOME.DATA
      LIST A, B, C, D
   ALWAYS
   LET C = MIN.F(C1, A2)
   LET D = MAX.F(D1, B2)
   LET KMAJOR = SPAN(I) / EKMN(I)
   LET KMINOR = EKMN(I)

   RETURN
END
ROUTINE TO LABEL.A.TICK.MARK
   GIVEN X, CP, VHFLAG

'' X IS THE REAL NUMBER ASSOCIATED WITH THE TICK.MARK TO BE PRINTED
'' CP IS THE CHARACTER POSITION OF WHERE THE TICK MARK IS LOCATED
'' VHFLAG = 1 IF TICK MARK IS ON THE X (HORIZONTAL AXIS)
''        = 2 IF THE TICK MARK IS ON THE Y (VERTICAL AXIS)

   DEFINE CP, VHFLAG, L, N, K AS INTEGER VARIABLES
   DEFINE X, AX, LAMDA, MU AS REAL VARIABLES

   IF X = 0.0
      LET L = 2 * VHFLAG - 1
      WRITE X AS B CP-L, D(3,1)
      RETURN
   OTHERWISE

   LET AX = ABS.F(X)
   IF AX GE 100000.0  OR AX LT .0001  ''USE E FORMAT
      LET L = 5 * VHFLAG
      WRITE X AS B CP-L, E(10,3)
      RETURN
   OTHERWISE

   LET LAMDA = LOG.10.F(AX)
   IF LAMDA GE 0.0
      LET N = TRUNC.F(LAMDA)
   ELSE  ''LAMDA ) 0.0
      LET MU = -LAMDA
      LET N = -TRUNC.F(MU)
      IF FRAC.F(MU) NE 0.0
         ADD -1 TO N
      ALWAYS
   ALWAYS

   LET K = 3 - N
   IF K ) 0
      LET K = 0
   ALWAYS
   IF VHFLAG = 2  ''VERTICAL AXIS
      LET L = 10
   ELSE ''VHFLAG = 1
      LET L = 7
      IF K > 4
         LET L = 6
      ALWAYS
      IF K = 7
         LET L = 5
      ALWAYS
      IF N = 4
         LET L = 6
      ALWAYS
   ALWAYS

   WRITE X AS B CP-L, D(10,K)

   RETURN
END
ROUTINE TO PRINT.THE.PRICE
   GIVEN PRICE

   DEFINE PRICE, DEFLATOR AS REAL VARIABLES
   DEFINE NCHAR AS AN INTEGER VARIABLE

   SKIP 2 LINES
   LET DEFLATOR = (1.0 + G.P) ** (REPORT.YEAR - SAVED(29))
   LET PRICE = PRICE * DEFLATOR

   WRITE AS B 1, "C(1) = "
   NOW WRITE.A.REAL.VALUE  GIVEN C(1), 5
   WRITE AS B 41, "EQPT = "
   NOW WRITE.A.REAL.VALUE  GIVEN EQPT.P * DEFLATOR, 5
   WRITE REPORT.YEAR AS B 61, "$(", I 4, ")"
   WRITE AS /

   WRITE AS B 1, "C(2) = "
   NOW WRITE.A.REAL.VALUE  GIVEN C(2) * DEFLATOR, 5
   WRITE REPORT.YEAR AS B 21, "$(", I 4, ")/SQFT", B 41, "SQFT = "
   NOW WRITE.A.REAL.VALUE  GIVEN SQFT.P, 5
   WRITE AS B 61, "SQ. FT."
   WRITE AS /

   WRITE AS B 1, "C(3) = "
   NOW WRITE.A.REAL.VALUE  GIVEN C(3), 5
   WRITE AS B 41, "DLAB = "
   NOW WRITE.A.REAL.VALUE  GIVEN DLAB.P * DEFLATOR, 5
   WRITE REPORT.YEAR AS B 61, "$(", I 4, ")/YR"
   WRITE AS /

   WRITE AS B 1, "C(4) = "
   NOW WRITE.A.REAL.VALUE  GIVEN C(4), 5
   WRITE AS B 41, "MATS = "
   NOW WRITE.A.REAL.VALUE  GIVEN MATS.P * DEFLATOR, 5
   WRITE REPORT.YEAR AS B 61, "$(", I 4, ")/YR"
   WRITE AS /

   WRITE AS B 1, "C(5) = "
   NOW WRITE.A.REAL.VALUE  GIVEN C(5), 5
   WRITE AS B 41, "UTIL = "
   NOW WRITE.A.REAL.VALUE  GIVEN UTIL.P * DEFLATOR, 5
   WRITE REPORT.YEAR AS B 61, "$(", I 4, ")/YR"
   WRITE AS /

   WRITE AS B 41, "P.QUAN = "
   NOW WRITE.A.REAL.VALUE  GIVEN P.QUAN, 5
   WRITE AS S 1
   NOW DETERMINE.CHARACTER.COUNT  GIVEN PROCESS.PRODUCT.UNITS  YIELDING NCHAR
   LET NCHAR = MIN.F(NCHAR, 9)
   NOW PRINT.CHARACTERS  GIVEN PROCESS.PRODUCT.UNITS, NCHAR
   WRITE AS "/YR"
   WRITE AS /

   WRITE AS B 41, "I.QUAN = "
   NOW WRITE.A.REAL.VALUE  GIVEN I.QUAN, 5
   NOW DETERMINE.CHARACTER.COUNT  GIVEN INDUSTRY.PRODUCTION.UNITS
      YIELDING NCHAR
   LET NCHAR = MIN.F(NCHAR, 9)
   WRITE AS S 1
   NOW PRINT.CHARACTERS  GIVEN INDUSTRY.PRODUCTION.UNITS, NCHAR
   WRITE AS "/YR"
   WRITE AS /

   SKIP 1 LINE
   IF PROCESS.FLAG = 0  ''PRINT PRICE
      WRITE AS B 1, "PRICE ="
   ELSE  ''PRINT VALUE ADDED
      WRITE AS B 1, "VALUE ADDED ="
   ALWAYS
   WRITE PRICE / I.QUAN AS D(9,4), " $("
   WRITE REPORT.YEAR AS I 4, ")/"
   NOW MOVE.TEXT  GIVEN INDUSTRY.PRODUCTION.UNITS, 0, 0
   NOW MAKE.THE.UNITS.SINGULAR
   WRITE PRICE / P.QUAN, REPORT.YEAR AS " => ", D(9,3), " $(", I 4, ")/"
   NOW MOVE.TEXT  GIVEN PROCESS.PRODUCT.UNITS, 0, 0
   NOW MAKE.THE.UNITS.SINGULAR
   WRITE AS /

   RETURN
END
ROUTINE TO READ.A.LINE.OF.TEXT  YIELDING TEXT.POINTER

   DEFINE TEXT.POINTER, I, START, END, WORDS, LAST.COLUMN AS INTEGER VARIABLES
   DEFINE TEXT AS A 1-DIM, ALPHA ARRAY
   DEFINE CPW TO MEAN CHARACTERS.PER.WORD

   ''TO SKIP EMPTY INPUT LINES FROM USER
   UNTIL CARD IS NOT NEW
       START NEW CARD

   NOW CHECK.THE.NEXT.INPUT.WORD.FOR.ABORT
   IF ABORT.FLAG = 1  ''ABORT
      RETURN
   OTHERWISE

   ''PREPARATION FOR READING
   LET START = SFIELD.F - 1
   LET RCOLUMN.V = START
   UNTIL CARD IS NEW
      SKIP 1 FIELD
   LET LAST.COLUMN = RCOLUMN.V
   LET END = MIN.F(START + 76, LAST.COLUMN)  ''LEADING BLANKS ARE SUPRESSED
   LET WORDS = ABS.ROUNDUP.F((END-START)/CPW)
   RESERVE TEXT AS WORDS
   LET RCOLUMN.V = START  ''READ BEGINNING IN START COLUMN
   ''ACTUAL READING
   FOR I = 1 TO WORDS-1
      READ TEXT(I) AS  A CPW
   READ TEXT(WORDS) AS  A END-RCOLUMN.V
   STORE TEXT(*) IN TEXT.POINTER
   IF CARD IS NOT NEW
      SAY "LINES ARE LIMITED TO 76 CHARACTERS, HENCE THIS LINE HAS ",
      "BEEN TRUNCATED TO:", /
      NOW QUOTE.TEXT  GIVEN TEXT.POINTER
      WRITE AS /
      LET RCOLUMN.V = LAST.COLUMN  ''TO SKIP REMAINDER PAST COL. 76
   ALWAYS
   RETURN

END
ROUTINE TO CHECK.THE.NEXT.INPUT.WORD.FOR.ABORT

   DEFINE TEXT.PTR, START, DUMMY AS INTEGER VARIABLES
   DEFINE MATCH.FLAG AS AN ALPHA VARIABLE

   UNTIL CARD IS NOT NEW
      START NEW CARD
   LET ABORT.FLAG = 0 ''SET FOR NO ABORT
   IF MODE IS NOT ALPHA
      RETURN
   OTHERWISE ''MODE IS ALPHA

   LET START = SFIELD.F - 1
   LET RCOLUMN.V = START
   NOW PUT.THE.NEXT.INPUT.WORD  YIELDING TEXT.PTR, DUMMY, DUMMY
   NOW COMPARE.STRINGS  GIVEN ABORT.PTR, TEXT.PTR
      YIELDING MATCH.FLAG
   RELEASE TEXT.PTR
   IF MATCH.FLAG = "M"
      LET ABORT.FLAG = 1 ''USER ENTERED ABORT
      RETURN
   OTHERWISE ''NO ABORT
   LET RCOLUMN.V = START
   RETURN

END
ROUTINE TO PUT.THE.NEXT.INPUT.WORD ''INTO A LOCALLY-DEFINED ALPHA ARRAY
   YIELDING TEXT, NO.OF.CHARACTERS, AND ''(OPTIONALLY)
      WORDS.OF.MEMORY.REQUIRED

''THIS ROUTINE USES THE CURRENT INPUT UNIT, POSITIONED EXACTLY AS IT IS TO:
''   1) DETERMINE THE NUMBER OF CHARACTERS IN THE WORD TO BE RETURNED
''   2) DETERMINE THE NUMBER OF COMPUTER WORDS REQUIRED TO STORE THE
''      TEXT WITH THIS PARTICULAR COMPUTER
''   3) PLACE THE CHARACTERS IN THE LOCALLY-DEFINED ALPHA ARRAY

   DEFINE NO.OF.CHARACTERS, WORDS.OF.MEMORY.REQUIRED, START,
      END, AND WORD AS INTEGER VARIABLES
   DEFINE TEXT AS A 1-DIMENSIONAL, ALPHA ARRAY
   DEFINE CPW TO MEAN CHARACTERS.PER.WORD ''A GLOBAL VARIABLE

   ''DETERMINE THE LENGTH OF THE TEXT
   LET START = SFIELD.F
   LET END = EFIELD.F
   LET NO.OF.CHARACTERS = END-START+1

   ''RESERVE A LOCALLY-DEFINED, ALPHA ARRAY TO STORE THE CHARACTERS
   ''CPW IS A GLOBAL VARIABLE FOR THE CHARACTERS/WORD OF THIS COMPUTER
   LET WORDS.OF.MEMORY.REQUIRED = DIV.F(NO.OF.CHARACTERS+CPW-1,CPW)
   RESERVE TEXT(*) AS WORDS.OF.MEMORY.REQUIRED

   ''READ THE CHARACTERS INTO THE ALPHA ARRAY
   READ AS B START ''MOVE POINTER TO START OF TEXT
   FOR WORD = 1 TO WORDS.OF.MEMORY.REQUIRED,
      READ TEXT(WORD) AS A MIN.F(CPW,END-RCOLUMN.V)
   RETURN
END
ROUTINE TO COMPARE.STRINGS  GIVEN STRING1, STRING2  YIELDING MATCH.FLAG

   DEFINE STRING1, STRING2, L1, L2, I AS INTEGER VARIABLES
   DEFINE TEXT1, TEXT2 AS 1-DIM, ALPHA ARRAYS
   DEFINE MATCH.FLAG AS AN ALPHA VARIABLE

   STORE STRING1 IN TEXT1(*)
   STORE STRING2 IN TEXT2(*)
   LET L1 = DIM.F(TEXT1(*))
   LET L2 = DIM.F(TEXT2(*))
   LET MATCH.FLAG = "M"
   IF L1 NE L2
      LET MATCH.FLAG = "NO.M"
      RETURN
   OTHERWISE
   FOR I = 1 TO L2, DO
      IF TEXT1(I) NE TEXT2(I)
         LET MATCH.FLAG = "NO.M"
         RETURN
      OTHERWISE
   LOOP
   RETURN

END
ROUTINE TO QUOTE.TEXT  GIVEN TEXT.POINTER

   DEFINE TEXT.POINTER AS AN INTEGER VARIABLE

   WRITE AS " _"
   NOW PRINT.TEXT  GIVEN TEXT.POINTER
   WRITE AS "_ "
   RETURN

END
ROUTINE TO PRINT.TEXT  GIVEN TEXT

   DEFINE L AND I AS INTEGER VARIABLES
   DEFINE TEXT AS A 1-DIM, ALPHA ARRAY

   IF TEXT(*) = 0
      PRINT 1 LINE THUS
NULL
      RETURN
   OTHERWISE

   LET L = DIM.F(TEXT(*))

   FOR I = 1 TO L,
      WRITE TEXT(I) AS A CHARACTERS.PER.WORD

   UNTIL OUT.F(WCOLUMN.V) NE " "  ''A BLANK
      SUBTRACT 1 FROM WCOLUMN.V   ''MOVE WRITING TEXT BACK

   RETURN

END
ROUTINE TO READ.A.REFERENT  YIELDING REFERENT.POINTER

   DEFINE END, REFERENT.POINTER, WORDS, I, OLD.EFIELD, J, START
      AS INTEGER VARIABLES
   DEFINE TEXT AS A 1-DIM, ALPHA ARRAY
   DEFINE CPW TO MEAN CHARACTERS.PER.WORD

   ''TO SKIP EMPTY INPUT LINES FROM USER
   ITERATING UNTIL CARD IS NOT NEW, DO
      START NEW CARD
      IF EOF.V = 2
         PRINT 1 LINE WITH READ.V THUS
UNEXPLAINED END OF FILE ENCOUNTERED ON UNIT **
         TRACE
         STOP
      OTHERWISE
      ADD 1 TO J
      IF J = 5
         SAY "PLEASE ENTER A REFERENT", /
         LET J = 0
      ALWAYS
   REPEAT ''UNTIL CARD IS NOT NEW

   NOW CHECK.THE.NEXT.INPUT.WORD.FOR.ABORT
   IF ABORT.FLAG = 1 ''ON
      RETURN
   OTHERWISE

   LET START = SFIELD.F
   LET OLD.EFIELD = EFIELD.F
   LET END = MIN.F(OLD.EFIELD, START + 8)
   LET WORDS = ABS.ROUNDUP.F((END-START+1)/CPW)
   RESERVE TEXT AS WORDS
   LET RCOLUMN.V = START - 1 ''READ AS BEGINNING IN START
   FOR I = 1 TO WORDS-1
      READ TEXT(I) AS  A CPW
   READ TEXT(WORDS)  AS  A END-RCOLUMN.V
   STORE TEXT(*) IN REFERENT.POINTER
   IF END ) OLD.EFIELD
      WRITE AS "A REFERENT IS LIMITED TO 9 CHARACTERS", /
      WRITE AS "THEREFORE, THIS REFERENT HAS BEEN TRUNCATED TO "
      NOW PRINT.TEXT GIVEN REFERENT.POINTER
      WRITE AS /
      SKIP 1 FIELD ''TO SKIP TRUNCATED PORTION OF USER'S INPUT
   ALWAYS
   RETURN

END
ROUTINE TO COPY.AN.ARRAY  GIVEN ORIGINAL  YIELDING COPY

   DEFINE ORIGINAL, COPY AS 1-DIM ARRAYS
   DEFINE I, LENGTH AS INTEGER VARIABLES

   LET LENGTH = DIM.F(ORIGINAL(*))
   RESERVE COPY AS LENGTH
   FOR I = 1 TO LENGTH
      STORE ORIGINAL(I) IN COPY(I)

   RETURN

END
ROUTINE TO POSITION.AN.ENTITY.FILE.TO.THE.FIRST.LINE.OF.THE.FIRST.ENTITY
   GIVEN FILE.NUMBER, NUMBER.IN.DIRECTORY
   YIELDING FILE.POS

   DEFINE FILE.NUMBER, NUMBER.IN.DIRECTORY, FILE.POS, SAVE.UNIT
      AS INTEGER VARIABLES

   IF NUMBER.IN.DIRECTORY = 0
      RETURN
   OTHERWISE

   STORE READ.V IN SAVE.UNIT
   REWIND FILE.NUMBER
   USE FILE.NUMBER FOR INPUT
   LET FILE.POS = NUMBER.IN.DIRECTORY + 2
   SKIP FILE.POS RECORDS
   STORE SAVE.UNIT IN READ.V

   RETURN
END
ROUTINE TO LOAD.SOME.TEXT YIELDING TEXT

''THIS ROUTINE MUST BE ENTERED WITH THE DESIRED TEXT IN "THE BUFFER" AND THE
''OUTPUT UNIT SET TO "THE BUFFER", FOR EXAMPLE,

''             LET XXX.UNIT = WRITE.V        (SAVES CURRENT OUTPUT UNIT)
''             USE THE BUFFER FOR OUTPUT
''             WRITE AS /, "THIS IS A TEST TO LOAD SOME TEXT"
''             NOW LOAD.SOME.TEXT YIELDING TEXTPTR

''LOAD.SOME.TEXT MOVES THE TEXT TO VECTOR TEXT AND RETURNS ITS POINTER TO
''THE CALLING ROUTINE.  IF "THE BUFFER" CONTAINS ALL BLANKS TEXTPTR = 0.
''IT IS THE RESPONSIBILITY OF THE CALLING ROUTINE TO RELEASE TEXT WHEN IT IS
''FINISHED WITH IT, FOR EXAMPLE,

''             STORE TEXTPTR IN SCRATCH(*)
''             RELEASE SCRATCH(*)

   DEFINE TEXT AS A 1-DIM, ALPHA ARRAY
   DEFINE NOC, N.WORDS, I AS INTEGER VARIABLES
   DEFINE CPW TO MEAN CHARACTERS.PER.WORD

   STORE 0 IN TEXT(*)
   LET NOC = BUFFER.V
   UNTIL OUT.F(NOC) NE " " OR NOC = 0
      SUBTRACT 1 FROM NOC

   IF NOC = 0
      RETURN
   OTHERWISE
   LET N.WORDS = DIV.F(NOC + CPW - 1, CPW)
   RESERVE TEXT(*) AS N.WORDS
   FOR I = 1 TO N.WORDS,
      READ TEXT(I) AS A CPW USING THE BUFFER
   LET WRITE.V = XXX.UNIT

   RETURN

END
ROUTINE ABS.ROUNDUP.F(REAL.NO)

   DEFINE REAL.NO AS A REAL VARIABLE
   DEFINE K AS AN INTEGER VARIABLE

   LET K = TRUNC.F(REAL.NO)
   IF REAL.NO NE K
      RETURN WITH K + 1

   OTHERWISE
   RETURN WITH K

END
ROUTINE TO INTERPRET.THE.USERS.NEXT.WORD
   GIVEN CONTEXT.USED, LINE.DISCARD.INDICATOR    YIELDING CASE.NUMBER

   DEFINE CONTEXT.USED, CASE.NUMBER, CHARS.OF.TEXT, WORDS.OF.TEXT,
      LAST.COLUMN.READ, HASHING.INDEX, POTENTIAL.WORD, MATCH.INDICATOR,
      VOCABULARY.WORD, MEANING, USAGE, COUNTER, EXCEPTION,
      LINE.DISCARD.INDICATOR  AS INTEGER VARIABLES

   ''L.D.I = 1 MEANS THAT A NEW CARD STATUS IS MEANINGFUL TO THE CALLING
   ''ROUTINE, SO RETURN WITH CASE.NUMBER = -1 INSTEAD OF STARTING A NEW CARD.
   ''L.D.I = 0 MEANS THAT NEW CARD STATUS IS NOT MEANINGFUL TO THE
   ''CALLING ROUTINE, AND IS JUST ANOTHER ERROR.
   ''GIVE USER 5 CHANCES TO RESPOND MEANINGFULLY
   ITERATING FOR COUNTER = 1 TO 5, DO

      IF CARD IS NEW  ''NO DATA LEFT ON THIS INPUT LINE
         IF LINE.DISCARD.INDICATOR = 1  ''ON
            LET CASE.NUMBER = -1  ''TO INDICATE NEW CARD STATUS
            RETURN
         OTHERWISE
         IF COUNTER > 1  ''NO ERROR MSG AFTER 1RST NEW CARD
            PRINT 1 LINE THUS
A BLANK LINE IS NOT MEANINGFUL IN THIS CONTEXT
            IF CONTEXT.MESSAGES(CONTEXT.USED) NE 0
               NOW PRINT.TEXT  GIVEN CONTEXT.MESSAGES(CONTEXT.USED)
               WRITE AS /
            ALWAYS
         ALWAYS
         START NEW CARD
         CYCLE
      OTHERWISE

      ''READ THE NEXT STRING INTO THE GLOBAL ARRAY USER.TEXT
      ''FIRST, RELEASE WHAT PREVIOUSLY OCCUPIED USER.TEXT
      RELEASE USER.TEXT
      NOW PUT.THE.NEXT.INPUT.WORD  ''INTO USER.TEXT
         YIELDING USER.TEXT(*), CHARS.OF.TEXT, WORDS.OF.TEXT
      LET LAST.COLUMN.READ = RCOLUMN.V

      ''DETERMINE WHICH HASHING PAGE TO CHECK FOR THE WORD
      STORE USER.TEXT(1) IN HASHING.INDEX  ''ALPHA TO INTEGER
      LET HASHING.INDEX = ABS.F(HASHING.INDEX)  ''DROP SIGN
      LET HASHING.INDEX = MOD.F(HASHING.INDEX,N.HASHING.PAGE) + 1

      ''CHECK EACH POTENTIAL WORD IN THE HASHING PAGE DETERMINED ABOVE
         ''FOR A MATCH
      ITERATING FOR EACH POTENTIAL.WORD IN VOCABULARY(HASHING.INDEX)
         WITH NUMBER.OF.CHARACTERS(POTENTIAL.WORD) = CHARS.OF.TEXT, DO

         NOW CHECK.FOR.A.MATCH  GIVEN POTENTIAL.WORD
            YIELDING MATCH.INDICATOR
         IF MATCH.INDICATOR = "M"  ''MATCH

            ''DETERMINE THE CASE.NUMBER IN THIS CONTEXT
            STORE POTENTIAL.WORD IN VOCABULARY.WORD
            FOR EACH MEANING IN DEFINITIONS(VOCABULARY.WORD)
               WITH CONTEXT(MEANING) = CONTEXT.USED,
            FIND USAGE = THE FIRST MEANING
            IF FOUND
               LET CASE.NUMBER = CASE.NO(USAGE)
               RETURN
            OTHERWISE  ''WORD USED OUT OF CONTEXT

            NOW QUOTE.TEXT  GIVEN USER.TEXT(*)
            WRITE AS "IS NOT RECOGNIZED IN THIS CONTEXT", /

            LET EXCEPTION = 1  ''FLAG SET TO AVOID PRINTING A SECOND MESSAGE
            LEAVE  ''THE LOOP OVER THE VOCABULARY(HASHING.INDEX)
         OTHERWISE  ''POTENTIAL WORD NOT A MATCH

         ''RESET READ COLUMN TO END OF USER.TEXT IN CASE CONTINUATION
            ''WORDS WERE READ IN CHECK.FOR.A.MATCH
         LET RCOLUMN.V = LAST.COLUMN.READ
      LOOP  ''OVER ALL POTENTIAL.WORDS IN THE HASHING PAGE

      ''PASSING THROUGH THE ABOVE LOOP MEANS THAT THERE IS NO MATCH AT ALL,
      ''OR A PREVIOUS EXCEPTION WAS ENCOUNTERED
      IF EXCEPTION = 0  ''NO PREVIOUS EXCEPTION - WORD NOT IN DICTIONARY
         NOW QUOTE.TEXT  GIVEN USER.TEXT(*)
         WRITE AS "IS NOT IN THE PROGRAM VOCABULARY", /
      ELSE
         LET EXCEPTION = 0  ''RESET FOR NEXT ITERATION
      ALWAYS

      ''ISSUE THE MESSAGE, IF IT EXISTS, FOR THIS CONTEXT
      IF CONTEXT.MESSAGES(CONTEXT.USED) NE 0
         NOW PRINT.TEXT  GIVEN CONTEXT.MESSAGES(CONTEXT.USED)
         WRITE AS /
      ALWAYS
      IF LINE.DISCARD.INDICATOR = 0  ''OFF
         ''L.D.I = 0 MEANS THAT REMAINDER OF LINE IS TO BE IGNORED IF
         ''AN ERROR IS DETECTED.
         START NEW CARD
      ALWAYS

   LOOP  ''UNTIL USER ENTERS MEANINGFUL RESPONSE

   ''PASSING THROUGH ABOVE LOOP MEANS USER ENTERED 5 CONSECUTIVE,
   ''UNRECOGNIZABLE RESPONSES
   PRINT 2 LINES THUS
YOUR TERMINAL SESSION IS BEING TERMINATED AFTER FIVE UNSUCCESSFUL ATTEMPTS
TO ENTER A MEANINGFUL RESPONSE.

   STOP

END
ROUTINE TO CHECK.FOR.A.MATCH
   GIVEN POTENTIAL.WORD  YIELDING MATCH.FLAG

   DEFINE MATCH.FLAG AS AN ALPHA VARIABLE
   DEFINE POTENTIAL.WORD AS AN INTEGER VARIABLE
   DEFINE TEXT AS A 1-DIM, ALPHA ARRAY

   ''MATCH USER.TEXT AGAINST POTENTIAL.WORD
   NOW COMPARE.STRINGS  GIVEN USER.TEXT(*) AND TEXT.POINTER(POTENTIAL.WORD)
      YIELDING MATCH.FLAG
   IF MATCH.FLAG = "NO.M"  ''NO MATCH
      RETURN
   OTHERWISE  ''USER.TEXT MATCHES POTENTIAL.WORD

   ''MAKE SURE USER ENTERS ALL CONTINUATION WORDS (IF ANY) OF POTENTIAL WORD
   STORE CONTINUATION.WORD(POTENTIAL.WORD) IN POTENTIAL.WORD
   ITERATING UNTIL POTENTIAL.WORD = 0, DO  ''UNTIL NO MORE CONTINUATION WORDS
      IF CARD IS NEW  ''INCOMPLETE PHRASE
         LET MATCH.FLAG = "NO.M"
         RETURN
      OTHERWISE

      ''PICK UP THE NEXT WORD
      NOW PUT.THE.NEXT.INPUT.WORD  ''INTO TEXT
         YIELDING TEXT(*)
      ''COMPARE WITH THE CONTINUATION WORD
      NOW COMPARE.STRINGS  GIVEN TEXT(*) AND TEXT.POINTER(POTENTIAL.WORD)
         YIELDING MATCH.FLAG
      RELEASE TEXT(*)
      IF MATCH.FLAG = "NO.M"  ''NO MATCH - INCOMPLETE PHRASE
         RETURN
      OTHERWISE

      ''TEST THE NEXT CONTINUATION WORD
      STORE CONTINUATION.WORD(POTENTIAL.WORD) IN POTENTIAL.WORD
   LOOP ''TO THE NEXT CONTINUATION.WORD

   ''PASSING THROUGH THE LOOP MEANS THAT USER'S WORD OR PHRASE MATCHED
   ''COMPLETELY WITH THE POTENTIAL WORD
   LET MATCH.FLAG = "M"
   RETURN

END
ROUTINE TO WRITE.A.REAL.VALUE  GIVEN REAL, N

   DEFINE REAL AS A REAL VARIABLE
   DEFINE N, M AS INTEGER VARIABLES

''THIS ROUTINE WRITES THE GIVEN REAL NUMBER IN EITHER D OR E FORMAT.
''IT WILL USE D(11,N) FORMAT PROVIDED THAT M SIGNIFICANT DIGITS OF ACCURACY
''CAN BE RETAINED; OTHERWISE IT USES E(11,5) FORMAT.  SINCE NUMBERS WHICH
''ARE TOO LARGE FOR A SPECIFIED D FORMAT WILL AUTOMATICALLY REVERT TO E FORMAT
''ONLY NUMBERS WHICH ARE TOO SMALL PRESENT A PROBLEM.  THIS IS HANDLED AS
''FOLLOWS:

''     IF ABS.F(REAL) GE 10 ** (M - N - 1)  USE D(11,N) FORMAT
''     IF ABS.F(REAL) LT 10 ** (M - N - 1)  USE E(11,5) FORMAT

   IF N ) 0 OR N > 9
      WRITE N AS /, "N =", I 5, " IS AN INVALID NUMBER OF DECIMAL PLACES "
      WRITE AS "FOR A FIELD OF WIDTH 10", /
      TRACE
      STOP
   OTHERWISE
   LET M = 5  ''SET FOR 5 SIGNIFICANT DIGITS

   IF ABS.F(REAL) GE 10.0 ** (M - N - 1)  OR REAL = 0.0
      WRITE REAL AS D(11,N)
   ELSE
      WRITE REAL AS E(11,5)
   ALWAYS

   RETURN
END
ROUTINE TO MAKE.THE.UNITS.SINGULAR

   DEFINE COL TO MEAN WCOLUMN.V

   IF OUT.F(COL) = "S"
      LET OUT.F(COL) = " "
      SUBTRACT 1 FROM COL
   ALWAYS

   RETURN

END
ROUTINE TO READ.A.REAL.VECTOR  GIVEN DEF.VECTOR.POINTER, MIN.VECTOR, MAX.VECTOR
   YIELDING VECTOR.POINTER

   DEFINE REAL.VECTOR, MIN.VECTOR, MAX.VECTOR AS 1-DIM, REAL ARRAYS
   DEFINE VECTOR.POINTER, I, INDEX, DEF.VECTOR.POINTER AS INTEGER VARIABLES
   DEFINE R1, R2 AS REAL VARIABLES
   DEFINE DCHECK, TAMPER.FLAG AS ALPHA VARIABLES

   ITERATING FOR INDEX = 1 TO 5, DO ''TO CHECK FOR UNACCEPTABLE INPUT
      UNTIL CARD IS NOT NEW,
         START NEW CARD
      ITERATING UNTIL MODE IS ALPHA, DO
         UNTIL CARD IS NOT NEW,
            START NEW CARD
         READ R2
         CREATE AN ELEMENT
         LET R1VALUE(ELEMENT) = R2
         FILE ELEMENT IN VECTOR
      LOOP
      NOW CHECK.THE.NEXT.INPUT.WORD.FOR.ABORT
      IF ABORT.FLAG = 1 ''ON
         GO TO ABORT
      OTHERWISE
      IF N.VECTOR ) 1
         ''SEE IF INPUT IS "D"
         READ DCHECK AS  A 2

         IF DCHECK = "D "  ''USER WANTS DEFAULT
            IF DEF.VECTOR.POINTER = 0  ''NO DEFAULT FOR THIS VECTOR
               PRINT 1 LINE THUS
A DEFAULT IS NOT AVAILABLE FOR THIS VECTOR
               START NEW CARD
               CYCLE  ''TO NEXT ATTEMPT AT ENTERING A VECTOR
            OTHERWISE  ''THE DEFAULT EXISTS, SO USE IT
            NOW COPY.AN.ARRAY  GIVEN DEF.VECTOR.POINTER
               YIELDING VECTOR.POINTER
            PRINT 1 LINE THUS
THIS VECTOR HAS BEEN DEFAULTED WITH THE FOLLOWING DATA:
            NOW WRITE.A.REAL.VECTOR  GIVEN VECTOR.POINTER
            RETURN
         OTHERWISE  ''FIRST INPUT IS ALPHA, BUT NOT "D"

         PRINT 1 LINE THUS
YOU HAVE TRIED TO INPUT AN EMPTY VECTOR.  PLEASE RE-ENTER YOUR VECTOR.
         START NEW CARD
         CYCLE
      OTHERWISE ''AN UNREAD ALPHA IS LEFT OVER, SO
      SKIP 1 FIELD
      LEAVE  ''INPUT IS ACCEPTABLE

   LOOP  ''UNTIL USER ENTERS ACCEPTABLE INPUT

   IF INDEX > 5  ''USER BLEW IT 5 TIMES
      PRINT 2 LINES THUS
YOUR RUN IS BEING TERMINATED AFTER 5 UNSUCCESSFUL ATTEMPTS AT
ENTERING A VECTOR.
      STOP
   OTHERWISE  ''USER HAS ENTERED A VECTOR THAT IS ACCEPTABLE

   ''PERFORM VALIDITY CHECKING
   LET DCHECK = "OK"  ''INITIALIZE FLAG
   ITERATING FOR INDEX = 1 TO 4, DO  ''ALLOW 4 PASSES OF CHECKING

      ''FIRST, MAKE SURE NO TWO ENTRIES ARE IDENTICAL
      LET R1 = R1VALUE(F.VECTOR)
      ITERATING FOR EACH ELEMENT AFTER F.VECTOR IN THE VECTOR, DO
         LET R2 = R1VALUE(ELEMENT)
         IF R2 = R1  ''DUPLICATE ENTRY
            WRITE R1 AS "A DUPLICATE OCCURRENCE OF THE VALUE ", E(11,4)
            WRITE AS "HAS BEEN DETECTED.  TO CORRECT", /
            SAY "THIS ERROR, THE LATTER OCCURRENCE WILL BE DELETED.", /
            REMOVE THIS ELEMENT FROM THE VECTOR
            DESTROY THIS ELEMENT
            LET TAMPER.FLAG = "ON"
         ALWAYS
         LET R1 = R2
      LOOP  ''FOR EACH ELEMENT

      ''MAKE SURE ALL NUMBERS ARE WITHIN RANGE
      ITERATING FOR EACH ELEMENT IN THE VECTOR, DO
         IF WORD.POINTER(ELEMENT) = 1  ''USER WANTS VALUE EVEN THOUGH
               ''IT IS OUTSIDE ITS LIMITS
            CYCLE
         OTHERWISE
         IF R1VALUE(ELEMENT) GE MIN.VECTOR(1) AND
               R1VALUE(ELEMENT) LE MAX.VECTOR(1)  ''NUMBER IS WITHIN LIMITS
            CYCLE  ''TO TEST NEXT NUMBER
         OTHERWISE  ''NUMBER IS OUT OF RANGE

         WRITE R1VALUE(ELEMENT) AS  "THE NUMBER ", E(11,4)
         WRITE AS " IS OUTSIDE ITS LIMITS.  DO YOU WISH TO RETAIN IT "
         WRITE AS "ANYWAY?", /
         START NEW CARD
         NOW CHECK.THE.NEXT.INPUT.WORD.FOR.ABORT
         IF ABORT.FLAG = 1 ''ON
            GO TO ABORT
         OTHERWISE
         NOW INTERPRET.THE.USERS.NEXT.WORD  GIVEN 1, 0  YIELDING ANSWER
         IF ANSWER = 1  ''YES
            LET WORD.POINTER(ELEMENT) = 1  ''INDICATE USER WANTS VALUE
               ''EVEN THOUGH OUTSIDE LIMITS
            CYCLE  ''TO NEXT NUMBER
         OTHERWISE  ''USER MUST ENTER NEW VALUE
         LET TAMPER.FLAG = "ON"  ''TO INDICATE TAMPERING
         NOW DISPLAY.THE.REAL.LIMITS  GIVEN -RINF.C, MIN.VECTOR(1),
            MAX.VECTOR(1)
         ''GET THE NEW NUMBER
         ITERATING UNTIL TERMINATED, DO  ''UNTIL A REAL IS ENTERED
            IF CARD IS NEW
               START NEW CARD
               CYCLE
            OTHERWISE
            NOW CHECK.THE.NEXT.INPUT.WORD.FOR.ABORT
            IF ABORT.FLAG = 1 ''ON
               GO TO ABORT
            OTHERWISE
            IF MODE IS ALPHA
               NOW DISPLAY.THE.REAL.LIMITS  GIVEN -RINF.C,
                  MIN.VECTOR(1), MAX.VECTOR(1)
               START NEW CARD
               CYCLE
            OTHERWISE
            READ R1VALUE(ELEMENT)
            LEAVE  ''THE LOOP WITH A NEW REAL NUMBER
         LOOP  ''UNTIL A REAL NUMBER IS ENTERED
         ''LEAVING ABOVE LOOP MEANS OLD NUMBER REPLACED WITH NEW - MUST
            ''PERFORM BOTH VALIDITY CHECKS AGAIN, SO
         LET DCHECK = "ERR"  ''SET FLAG TO REITERATE CHECKING
      LOOP  ''FOR THE NEXT ELEMENT

      ''REITERATE BOTH CHECKS ABOVE IF ANY ERROR WAS DETECTED
      IF DCHECK = "OK"  ''NO ERROR WAS FOOND ABOVE
         RESERVE REAL.VECTOR AS N.VECTOR
         ITERATING FOR EACH ELEMENT IN THE VECTOR, DO
            ADD 1 TO I
            LET REAL.VECTOR(I) = R1VALUE(ELEMENT)
            REMOVE THIS ELEMENT FROM THE VECTOR
            DESTROY THIS ELEMENT
         LOOP  ''FOR EACH ELEMENT
         STORE REAL.VECTOR(*) IN VECTOR.POINTER
         IF TAMPER.FLAG  = "ON"  ''VECTOR HAS BEEN ALTERED AND MUST BE
               ''PRINTED TO SHOW USER THE CHANGES
            PRINT 2 LINES THUS
MODIFICATION OF THE ORIGINAL VECTOR IS NOW COMPLETE.  THE REVISED VECTOR
IS AS FOLLOWS:
            NOW WRITE.A.REAL.VECTOR  GIVEN VECTOR.POINTER
         ALWAYS
         RETURN
      OTHERWISE  ''AN ERROR WAS FOUND ABOVE
      NOW REORDER.THE.VECTOR  ''FOR THE NEXT PASS
      LET DCHECK = "OK"  ''FOR NEXT PASS

   LOOP  ''FOR EACH PASS AT VALIDITY CHECKING

   ''FALLING THROUGH LOOP MEANS THAT UNRESOLVED ERRORS REMAIN
   PRINT 2 LINES THUS
YOUR VECTOR IS STILL INCORRECT AFTER 4 ATTEMPTS TO CORRECT IT.
PLEASE CONSULT THE USER'S GUIDE.
   STOP

   'ABORT'   ''HERE IF USER ENTERS ABORT

      RELEASE REAL.VECTOR(*)
      STORE 0 IN VECTOR.POINTER
      ITERATING FOR EACH ELEMENT IN VECTOR, DO
         REMOVE THIS ELEMENT FROM THE VECTOR
         DESTROY THIS ELEMENT
      REPEAT ''FOR NEXT ELEMENT
      RETURN

END
ROUTINE TO MOVE.TEXT GIVEN TEXT, BEGIN, END

''THIS ROUTINE MOVES A 1-DIM, ALPHA ARRAY INTO THE CURRENT OUTPUT BUFFER
''BEGINNING AT COLUMN BEGIN AND ENDING AT COLUMN END.
''DEFAULT BEGIN IS WCOLUMN.V+1. IF IT IS NEAR THE END, IT IS SET TO 1.
''DEFAULT END IS LINE.LENGTH(RUN.CONTROL).
''DEFAULT FOR NO APPROPRIATE WORD ENDING OR MORE THAN 3 LINES REQUIRED
''IS WRAP AROUND USING PRINT.TEXT.

   DEFINE CPW TO MEAN CHARACTERS.PER.WORD
   DEFINE PCOL TO MEAN WCOLUMN.V

   DEFINE TEXT, SUB AS 1-DIM, ALPHA ARRAYS
   DEFINE BLANK, WORD AS ALPHA VARIABLES
   DEFINE BEGIN, END, POINT, LENGTH AS INTEGER VARIABLES
   DEFINE DIM, CHARS, BCOL AS INTEGER VARIABLES
   DEFINE I, J, K, L, M, MM, N AS INTEGER VARIABLES

   DEFINE TEMP, OUT AS INTEGER VARIABLES

   IF TEXT(*) = 0
      PRINT 1 LINE THUS
NULL
      RETURN
   OTHERWISE

   LET DIM = DIM.F(TEXT(*))
''**********
   LET LENGTH = 79  ''LINE.LENGTH(RUN.CONTROL)
''**********
   IF END NE 0
      LET LENGTH = END
   ALWAYS
   NOW DETERMINE.CHARACTER.COUNT GIVEN TEXT(*) YIELDING CHARS
   LET POINT = WCOLUMN.V+1
   IF BEGIN NE 0
      IF POINT GT BEGIN
         WRITE AS / ''DONT OVERWRITE THE CURRENT CONTENTS
      ALWAYS
      LET POINT = BEGIN
   ALWAYS
   IF POINT GE LENGTH-CPW ''TOO NEAR THE END OF LINE
      IF WCOLUMN.V GT 1
         WRITE AS / ''DUMP PRESENT CONTENTS OF LINE FIRST
      ALWAYS
      LET POINT = 1
   ALWAYS
   LET L = LENGTH-POINT
   IF CHARS LE L
      NOW PRINT.TEXT GIVEN TEXT(*)
      RETURN
   OTHERWISE

   LET N = TRUNC.F(CHARS/L)
   IF MOD.F(L,CHARS) NE 0
      ADD 1 TO N
   ALWAYS
   IF N GT 3
      NOW PRINT.TEXT GIVEN TEXT(*)
      RETURN
   OTHERWISE

''PUT TEXT INTO THE BUFFER
   WRITE AS / USING THE BUFFER
   ITERATING FOR J = 1 TO DIM, DO
      WRITE TEXT(J) AS A CPW USING THE BUFFER
   REPEAT ''TO END OF TEXT

   LET BLANK = "  "
   LET BCOL = 0
   LET PCOL = POINT-1

''MOVE FROM BUFFER TO PRINT
   ITERATING FOR I = 1 TO N, DO
      LET K = 1
'BEGIN'
      ITERATING FOR J = K TO L, DO
         ADD 1 TO BCOL
         ADD 1 TO PCOL
         IF BCOL EQ CHARS+1
            RETURN ''END OF TEXT
         OTHERWISE

         READ WORD AS B BCOL, A 1 USING THE BUFFER
         LET OUT.F(PCOL) = WORD
         IF J = 1 AND WORD = BLANK ''A LEADING BLANK
            LET K = 2
            SUBTRACT 1 FROM PCOL
            GO TO BEGIN
         OTHERWISE

      REPEAT ''TO END OF THE LINE

      LET K = PCOL
      READ WORD AS B BCOL+1, A 1 USING THE BUFFER
      IF WORD EQ BLANK ''WE HAVE A WORD SEPARATOR HERE
        JUMP AHEAD
      OTHERWISE

''FIND A WORD SEPARATOR
      ITERATING FOR J BACK FROM K TO POINT, DO
         IF OUT.F(J) = BLANK
            LEAVE
         OTHERWISE

         LET OUT.F(J) = BLANK
         SUBTRACT 1 FROM BCOL
         IF BCOL LT 1
            LET BCOL = 1
         ALWAYS
         IF J LE POINT
            LET M = DIM-TRUNC.F(BCOL/CPW)
            RESERVE SUB(*) AS M

            ITERATING FOR MM = 1 TO M, DO
               READ SUB(MM) AS B BCOL, A CPW USING THE BUFFER
               LET BCOL = BCOL+CPW
            REPEAT ''TO END OF SUBSTRING

            WRITE AS /
            LET PCOL = 1
            NOW PRINT.TEXT GIVEN SUB(*)
            RELEASE SUB(*)
            RETURN
         OTHERWISE

      REPEAT ''UNTIL AN END OF WORD

      HERE
      WRITE AS /
      LET PCOL = POINT-1
      LET K = 1
      IF BCOL+1 LT CHARS AND I EQ N
         GO TO BEGIN ''TO REACQUIRE THE LAST LINE
      OTHERWISE

   REPEAT ''UNTIL END OF TEXT

END
ROUTINE TO DETERMINE.CHARACTER.COUNT GIVEN TEXT YIELDING NUMBER.OF.CHARACTERS

''THIS ROUTINE DETERMINES THE CHARACTER COUNT (BY EXCLUDING ALL TRAILING
''BLANKS) IN A GIVEN TEXT VECTOR.  IF THE TEXT VECTOR IS UNASSIGNED OR THE
''TEXT IS ALL BLANKS, A COUNT OF ZERO IS RETURNED.

   DEFINE CPW TO MEAN CHARACTERS.PER.WORD
   DEFINE TEXT AS A 1-DIM, ALPHA ARRAY
   DEFINE NUMBER.OF.CHARACTERS, L, OUT.UNIT, I, J AS INTEGER VARIABLES

   LET NUMBER.OF.CHARACTERS = 0
   IF TEXT(*) = 0
      RETURN
   OTHERWISE
      LET L = DIM.F(TEXT(*))
      LET OUT.UNIT = WRITE.V
      LET NUMBER.OF.CHARACTERS = L*CPW
      USE THE BUFFER FOR OUTPUT

      ITERATING FOR I BACK FROM L TO 1, DO
         WRITE TEXT(I) AS /, A CPW

         ITERATING ALSO FOR J BACK FROM CPW TO 1, DO
            IF OUT.F(J) NE " "
               LEAVE ''THE LOOP
            OTHERWISE
            LET NUMBER.OF.CHARACTERS = NUMBER.OF.CHARACTERS - 1
      REPEAT ''FOR EACH J AND I

   USE OUT.UNIT FOR OUTPUT
   RETURN
END
ROUTINE TO RELEASE.A.TEXT.VECTOR  GIVEN TEXT.VECTOR

   DEFINE TEXT.VECTOR AS A 1-DIM, INTEGER ARRAY
   DEFINE I AS AN INTEGER VARIABLE

   IF TEXT.VECTOR(*) = 0
      RETURN
   OTHERWISE
   FOR I = 1 TO DIM.F(TEXT.VECTOR(*)),
      RELEASE TEXT.VECTOR(I)
   RELEASE TEXT.VECTOR(*)
   RETURN

END
ROUTINE TO INTERPRET.THE.NEXT.WORD.IF.NOT.ABORT   GIVEN PARSER.CONTEXT
   YIELDING MEANING.NUMBER

   DEFINE PARSER.CONTEXT, MEANING.NUMBER, ERROR.COUNT  AS INTEGER VARIABLES

   ITERATING FOR ERROR.COUNT = 1 TO 4, DO
      IF CARD IS NEW
         IF ERROR.COUNT > 1
            NOW PRINT.TEXT  GIVEN CONTEXT.MESSAGES(PARSER.CONTEXT)
            WRITE AS /
         ALWAYS
         START NEW CARD
         CYCLE
      OTHERWISE
      NOW CHECK.THE.NEXT.INPUT.WORD.FOR.ABORT
      IF ABORT.FLAG = 1  ''ABORT
         RETURN
      OTHERWISE
      NOW INTERPRET.THE.USERS.NEXT.WORD  GIVEN PARSER.CONTEXT, 0
         YIELDING MEANING.NUMBER
      RETURN
   LOOP  ''UNTIL NONBLANK IS ENTERED

   ''DROPPING THROUGH LOOP MEANS 4 CONSECUTIVE BLANKS WERE ENTERED
   PRINT 1 LINE THUS
IPEG EXECUTION TERMINATED AFTER RECEIVING 4 UNACCEPTABLE USER RESPONSES.
   STOP

END
ROUTINE TO READ.A.TEXT.VECTOR.FROM.FILE  YIELDING TEXT.VECTOR

   DEFINE TEXT.VECTOR AS A 1-DIM, INTEGER ARRAY
   DEFINE I AS AN INTEGER VARIABLE
   DEFINE TEXT AS A 1-DIM, ALPHA ARRAY

   ITERATING UNTIL TERMINATED, DO
      NOW READ.A.REFERENT  YIELDING TEXT(*)
      IF DIM.F(TEXT(*)) = 1 AND TEXT(1) = "* "
         LEAVE  ''THE LOOP
      OTHERWISE
      CREATE AN ELEMENT
      STORE TEXT(*) IN WORD.POINTER(ELEMENT)
      FILE THIS ELEMENT IN THE VECTOR
   LOOP

   ''PUT VECTOR INTO TEXT.VECTOR
   RESERVE TEXT.VECTOR AS N.VECTOR
   ITERATING FOR EACH ELEMENT IN THE VECTOR, DO
      ADD 1 TO I
      REMOVE THIS ELEMENT FROM THE VECTOR
      STORE WORD.POINTER(ELEMENT) IN TEXT.VECTOR(I)
      DESTROY THIS ELEMENT
   LOOP
   RELEASE TEXT(*)
   RETURN

END
ROUTINE TO WRITE.A.TEXT.VECTOR  GIVEN VECTOR.POINTER

   DEFINE TEXT.VECTOR AS A 1-DIM, INTEGER ARRAY
   DEFINE VECTOR.POINTER, I, LENGTH, LINES, J AS INTEGER VARIABLES

   ''WRITE 7 REFERENTS PER LINE

   STORE VECTOR.POINTER IN TEXT.VECTOR(*)
   LET LENGTH = DIM.F(TEXT.VECTOR(*))
   ''WRITE ALL BUT LAST LINE
   LET LINES = ABS.ROUNDUP.F(LENGTH/7)-1
   FOR I = 1 TO LINES, DO
      WRITE AS B 1
      FOR J = 7*I-6 TO 7*I, DO
         WRITE AS S 1
         NOW PRINT.TEXT  GIVEN TEXT.VECTOR(J)
      LOOP
      WRITE AS /
   LOOP
   ''WRITE LAST LINE
   WRITE AS B 1
   FOR I = 7*LINES+1 TO LENGTH, DO
      WRITE AS  S 1
      NOW PRINT.TEXT  GIVEN TEXT.VECTOR(I)
   LOOP
   WRITE AS S 1, "*", /

RETURN

END
ROUTINE TO DISPLAY.THE.REAL.LIMITS  GIVEN DEFAULT, MIN, MAX

   DEFINE DEFAULT, MIN, MAX  AS REAL VARIABLES

   SAY  "PLEASE ENTER A REAL NUMBER"

   IF MIN NE -RINF.C
      WRITE MIN AS  " GREATER THAN OR EQUAL TO ",  E(11,4)
   ALWAYS

   IF MAX NE RINF.C
      IF MIN NE -RINF.C
         WRITE AS  " AND"
      ALWAYS
      WRITE MAX AS  " LESS THAN OR EQUAL TO ",  E(11,4)
   ALWAYS

   IF DEFAULT NE -RINF.C
      WRITE AS  " OR _D_ FOR _DEFAULT_"
   ALWAYS

   WRITE AS  ".", /
   RETURN

END
ROUTINE TO READ.A.REAL  GIVEN DEFAULT.VALUE, MIN.VALUE, MAX.VALUE
   YIELDING REAL.VALUE

   DEFINE DEFAULT.VALUE, MIN.VALUE, MAX.VALUE, REAL.VALUE AS REAL VARIABLES
   DEFINE TEXT.PTR, I, CASE.NUMBER  AS INTEGER VARIABLES
   DEFINE DCHECK AS AN ALPHA VARIABLE

   FOR I = 1 TO 5, DO  ''TO CHECK FOR UNACCEPTABLE DATA
      UNTIL CARD IS NOT NEW
         START NEW CARD
      LET START = SFIELD.F - 1
      LET RCOLUMN.V = START

      NOW CHECK.THE.NEXT.INPUT.WORD.FOR.ABORT
      IF ABORT.FLAG = 1 ''ON
         RETURN
      OTHERWISE

      IF MODE IS ALPHA
         ''SEE IF INPUT IS "D" ''
         READ DCHECK AS  A 2

         IF DCHECK = "D "
            IF DEFAULT.VALUE NE -RINF.C
               LET REAL.VALUE = DEFAULT.VALUE
               WRITE AS "THE DEFAULT, "
               NOW WRITE.A.REAL.VALUE  GIVEN REAL.VALUE, 4
               WRITE AS ", HAS BEEN ASSUMED.", /
               RETURN
            OTHERWISE
            PRINT 1 LINE THUS
A DEFAULT VALUE IS NOT AVAILABLE FOR THIS VARIABLE
            NOW DISPLAY.THE.REAL.LIMITS  GIVEN DEFAULT.VALUE, MIN.VALUE,
               MAX.VALUE
            CYCLE
         OTHERWISE

         LET RCOLUMN.V = START
         NOW PUT.THE.NEXT.INPUT.WORD  YIELDING TEXT.PTR
         NOW QUOTE.TEXT  GIVEN TEXT.PTR
         WRITE AS  "WAS NOT ACCEPTED, SO THE REMAINDER OF THE LINE HAS"
         WRITE AS  " BEEN IGNORED.", /
         NOW DISPLAY.THE.REAL.LIMITS  GIVEN DEFAULT.VALUE, MIN.VALUE,
            MAX.VALUE
         START NEW CARD
         CYCLE
      OTHERWISE

      READ REAL.VALUE
      IF REAL.VALUE GE MIN.VALUE AND REAL.VALUE LE MAX.VALUE
         RETURN
      OTHERWISE
      WRITE AS B 1
      NOW WRITE.A.REAL.VALUE  GIVEN REAL.VALUE, 4
      WRITE AS " IS OUTSIDE THE LIMITS FOR THIS VARIABLE.", /
      WRITE AS "DO YOU WISH TO RETAIN IT ANYWAY?", /
      START NEW CARD
      NOW CHECK.THE.NEXT.INPUT.WORD.FOR.ABORT
      IF ABORT.FLAG = 1 ''ON
         RETURN
      ALWAYS
      NOW INTERPRET.THE.USERS.NEXT.WORD  GIVEN 1, 0  YIELDING CASE.NUMBER
      IF CASE.NUMBER = 1  ''YES
         RETURN
      OTHERWISE  ''CASE.NUMBER = 2, NO
      NOW DISPLAY.THE.REAL.LIMITS  GIVEN DEFAULT.VALUE, MIN.VALUE,
         MAX.VALUE
    LOOP
   PRINT 1 LINE THUS
YOUR RUN IS BEING TERMINATED AFTER ENTERING 5 UNACCEPTABLE RESPONSES.
   TRACE
   STOP

END
ROUTINE TO READ.AN.INTEGER  GIVEN DEFAULT.VALUE, MIN.VALUE, MAX.VALUE,
   REJECT.FLAG
   YIELDING ACTUAL.VALUE

   DEFINE DEFAULT.VALUE, MIN.VALUE, MAX.VALUE, ACTUAL.VALUE, INDEX, TEXT.PTR,
      ANSWER, REJECT.FLAG  AS INTEGER VARIABLES
   DEFINE REAL.VALUE AS A REAL VARIABLE
   DEFINE DCHECK AS AN ALPHA VARIABLE

   ITERATING FOR INDEX = 1 TO 5, DO
      UNTIL CARD IS NOT NEW
         START NEW CARD
      LET START = SFIELD.F - 1
      LET RCOLUMN.V = START

      NOW CHECK.THE.NEXT.INPUT.WORD.FOR.ABORT
      IF ABORT.FLAG = 1 ''ON
         RETURN
      OTHERWISE

      IF MODE IS ALPHA
         ''SEE IF INPUT IS "D"
         READ DCHECK AS  A 2

         IF DCHECK = "D "
            IF DEFAULT.VALUE NE -INF.C
               LET ACTUAL.VALUE = DEFAULT.VALUE
               PRINT 1 LINE WITH ACTUAL.VALUE THUS
THE DEFAULT, ********, HAS BEEN ASSUMED.
               RETURN
            OTHERWISE
            PRINT 1 LINE THUS
A DEFAULT VALUE IS NOT AVAILABLE FOR THIS VARIABLE
            NOW DISPLAY.THE.INTEGER.LIMITS  GIVEN DEFAULT.VALUE,
               MIN.VALUE, MAX.VALUE
            CYCLE
         OTHERWISE

         LET RCOLUMN.V = START  ''BACK UP TO BEGINNING
         NOW PUT.THE.NEXT.INPUT.WORD  YIELDING TEXT.PTR
         NOW QUOTE.TEXT  GIVEN TEXT.PTR
         WRITE AS "WAS NOT ACCEPTED, SO THE REMAINDER OF THE LINE HAS "
         WRITE AS "BEEN IGNORED.", /
         NOW DISPLAY.THE.INTEGER.LIMITS  GIVEN DEFAULT.VALUE, MIN.VALUE,
            MAX.VALUE
         START NEW CARD
         CYCLE
      OTHERWISE

      IF MODE IS REAL
         READ REAL.VALUE
         LET ACTUAL.VALUE = REAL.VALUE
         PRINT 1 LINE WITH REAL.VALUE, ACTUAL.VALUE THUS
REAL INPUT, ****.*****, HAS BEEN CONVERTED TO INTEGER, ********.
      ELSE
         READ ACTUAL.VALUE
      ALWAYS

      IF ACTUAL.VALUE GE MIN.VALUE AND ACTUAL.VALUE LE MAX.VALUE
         RETURN
      OTHERWISE
      IF REJECT.FLAG = 0 ''ACCEPT OUT OF BOUNDS VALUES IF USER SAYS OK
         PRINT 2 LINES WITH ACTUAL.VALUE THUS
********** IS OUTSIDE THE LIMITS OF THIS VARIABLE.
DO YOU WISH TO RETAIN IT ANYWAY?
         START NEW CARD
         NOW CHECK.THE.NEXT.INPUT.WORD.FOR.ABORT
         IF ABORT.FLAG = 1 ''ON
            RETURN
         OTHERWISE
         NOW INTERPRET.THE.USERS.NEXT.WORD  GIVEN 13, 0  YIELDING ANSWER
         IF ANSWER = 1  ''YES
            RETURN
         OTHERWISE
         NOW DISPLAY.THE.INTEGER.LIMITS GIVEN DEFAULT.VALUE, MIN.VALUE,
            MAX.VALUE
      ELSE ''REJECT.FLAG NE 0 REQUIRE USER TO SUPPLY IN BOUNDS VALUE
         PRINT 2 LINES WITH ACTUAL.VALUE THUS
********** IS OUTSIDE THE LIMITS OF THIS VARIABLE.  YOU ARE REQUIRED TO ENTER
AN ACCEPTABLE VALUE.
         NOW DISPLAY.THE.INTEGER.LIMITS GIVEN DEFAULT.VALUE, MIN.VALUE,
            MAX.VALUE
         START NEW CARD
      ALWAYS

   REPEAT ''FOR NEXT READ ATTEMPT

   PRINT 1 LINE THUS
YOUR RUN IS BEING TERMINATED AFTER 5 UNNACCEPTABLE RESPONSES.
   TRACE
   STOP

END
ROUTINE TO DISPLAY.THE.INTEGER.LIMITS  GIVEN DEFAULT, MIN, MAX

   DEFINE DEFAULT, MIN, MAX  AS INTEGER VARIABLES

   SAY  "PLEASE ENTER AN INTEGER NUMBER"

   IF MIN NE -INF.C
      WRITE MIN AS  " GREATER THAN OR EQUAL TO ",  I 11
   ALWAYS

   IF MAX NE INF.C
      IF MIN NE -RINF.C
         WRITE AS  " AND"
      ALWAYS
      WRITE MAX AS  " LESS THAN OR EQUAL TO ",  I 11
   ALWAYS

   IF DEFAULT NE -INF.C
      WRITE AS  " OR _D_ FOR _DEFAULT_"
   ALWAYS

   WRITE AS  ".", /
   RETURN

END
ROUTINE TO CHANGE.A.REAL  GIVEN OLD.VALUE, DEFAULT, MIN, MAX
   YIELDING NEW.VALUE

   DEFINE OLD.VALUE, DEFAULT, MIN, MAX, NEW.VALUE AS REAL VARIABLES
   DEFINE SAVE.TEXT AS AN INTEGER VARIABLE

   ''AVOID POSSIBLE CLOBBERING OF TEXT BY PARSER (CALLED FROM READ.A.REAL)
   NOW COPY.AN.ARRAY  GIVEN USER.TEXT(*) ''GLOBAL''  YIELDING SAVE.TEXT
   NOW READ.A.REAL  GIVEN DEFAULT, MIN, MAX  YIELDING NEW.VALUE
   IF ABORT.FLAG = 1  ''ABORT
      SAY "***** YOUR CHANGE COMMAND HAS BEEN ABORTED.", /
      LET NEW.VALUE = OLD.VALUE
      RELEASE SAVE.TEXT
      RETURN
   OTHERWISE
   NOW PRINT.TEXT  GIVEN SAVE.TEXT
   WRITE OLD.VALUE AS " CHANGED FROM: ", E(11,5)
   WRITE NEW.VALUE AS " TO: ", E(11,5), /
   RELEASE SAVE.TEXT
   RETURN

END
ROUTINE TO WRITE.A.REAL.VECTOR GIVEN VECTOR

   DEFINE I, J, LINES, LENGTH AS INTEGER VARIABLES
   DEFINE VECTOR AS A 1-DIM REAL ARRAY

   SUBSTITUTE THESE 3 LINES FOR INSERT.PLUS
      IF OUT.F(WCOLUMN.V - 2) = " "
         LET OUT.F(WCOLUMN.V - 2) = "+"
      ALWAYS

   IF VECTOR(*) = 0  ''VECTOR DOES NOT EXIST
      SAY "(NULL)", /
      RETURN
   OTHERWISE  ''VECTOR EXISTS AND CAN BE WRITTEN

   '' WRITE 5 REALS PER LINE

   LET LENGTH = DIM.F(VECTOR(*))
   LET LINES = ABS.ROUNDUP.F(LENGTH/5)-1

   '' WRITE ALL BUT LAST LINE
   ITERATING FOR I = 1 TO LINES, DO
      WRITE AS B 1
      ITERATING FOR J = 5*I - 4 TO 5*I, DO
         WRITE AS S 1
         IF WRITE.V = NORMAL.OUTPUT.UNIT
            NOW WRITE.A.REAL.VALUE  GIVEN VECTOR(J), 4
         ELSE ''WRITING TO FILE
            WRITE VECTOR(J) AS E(11,5)   INSERT.PLUS
         ALWAYS
      REPEAT ''FOR NEXT NUMBER
      WRITE AS /
   REPEAT ''FOR NEXT LINE

   ''WRITE LAST LINE
   WRITE AS B 1
   ITERATING FOR I = 5*LINES+1 TO LENGTH, DO
      WRITE AS S 1
      IF WRITE.V = NORMAL.OUTPUT.UNIT
         NOW WRITE.A.REAL.VALUE  GIVEN VECTOR(I), 4
      ELSE ''WRITING TO FILE
         WRITE VECTOR(I) AS E(11,5)   INSERT.PLUS
      ALWAYS
   REPEAT ''FOR NEXT NUMBER
   WRITE AS S 1, "*", /

   RETURN

END
ROUTINE TO REORDER.THE.VECTOR

   DEFINE SAVE.ARRAY AS A 1-DIM, INTEGER ARRAY
   DEFINE I AS AN INTEGER VARIABLE

   RESERVE SAVE.ARRAY AS N.VECTOR
   ITERATING FOR EACH ELEMENT IN THE VECTOR, DO
      ADD 1 TO I
      STORE ELEMENT IN SAVE.ARRAY(I)
      REMOVE THIS ELEMENT FROM THE VECTOR
   LOOP  ''FOR EACH ELEMENT

   ''PUT ARRAY BACK INTO VECTOR
   FOR I = 1 TO DIM.F(SAVE.ARRAY(*)), DO
      STORE SAVE.ARRAY(I) IN ELEMENT
      FILE THIS ELEMENT IN THE VECTOR
   LOOP  ''THROUGH SAVE.ARRAY
   RELEASE SAVE.ARRAY
   RETURN

END
ROUTINE TO CHECK.THE.NEXT.NONBLANK.LINE.FOR.DEFAULT
   YIELDING DEFAULT.FLAG

''THIS ROUTINE CHECKS THE NEXT NONBLANK LINE FOR A "D" WHICH INDICATES DEFAULT
''IF "D" IS DETECTED AND THERE IS NOTHING ELSE ON THE LINE, SETS DEFAULT.FLAG
''TO 1; OTHERWISE, SETS DEFAULT.FLAG = 0.

   DEFINE DEFAULT.FLAG, START AS INTEGER VARIABLES
   DEFINE CHARACTER AS AN ALPHA VARIABLE

   UNTIL CARD IS NOT NEW
      START NEW CARD

   LET DEFAULT.FLAG = 0

   IF EFIELD.F NE SFIELD.F  ''CAN'T BE "D"
      RETURN
   OTHERWISE

   LET START = SFIELD.F - 1
   LET RCOLUMN.V = START
   READ CHARACTER AS A 1
   IF CARD IS NOT NEW  ''MORE STUFF ON CARD; HENCE, CAN'T BE "D"
      LET RCOLUMN.V = START
      RETURN
   OTHERWISE
   IF CHARACTER = "D"  ''DEFAULT
      LET DEFAULT.FLAG = 1
   ELSE
      LET RCOLUMN.V = START
   ALWAYS
   RETURN

END
ROUTINE TO PRINT.CHARACTERS GIVEN TEXT, NUMBER.OF.CHARACTERS

   DEFINE CPW TO MEAN CHARACTERS.PER.WORD
   DEFINE TEXT AS A 1-DIM, ALPHA ARRAY
   DEFINE NUMBER.OF.CHARACTERS, NWORDS, I, L AS INTEGER VARIABLES

   IF NUMBER.OF.CHARACTERS LE 0
      RETURN
   OTHERWISE
   IF NUMBER.OF.CHARACTERS LE CPW
      WRITE TEXT(1) AS A NUMBER.OF.CHARACTERS
      RETURN
   OTHERWISE
      LET NWORDS = 1+DIV.F(NUMBER.OF.CHARACTERS-1,CPW)
      FOR I = 1 TO NWORDS-1, WRITE TEXT(I) AS A CPW
      LET L = NUMBER.OF.CHARACTERS-(NWORDS-1)*CPW
      WRITE TEXT(NWORDS) AS A L
      RETURN
END
